home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 07 - 1991 / 07.10 Oct 91 / Window Menubar Source ƒ / wBarMenuProc.p < prev    next >
Encoding:
Text File  |  1991-07-26  |  64.9 KB  |  2,223 lines  |  [TEXT/PJMM]

  1. { ******************************************************** }
  2. { "wBarMenuProc.p"                                         }
  3. {                                                          }
  4. { by:                                                      }
  5. {      James Matthews                                      }
  6. {         < MacTutor -- Nov 88 >                           }
  7. {                                                          }
  8. { with color + hierarchical Menu support                   }
  9. { and other nifty additions by:                            }
  10. {      John A. Love, III                                   }
  11. {         [ Washington Apple Pi Users' Group]              }
  12. {                                                          }
  13. { using Symantec's "THINK Lightspeed Pascal", v 3.02       }
  14. {                                                          }
  15. { ******************************************************** }
  16.  
  17.  
  18.  
  19.  
  20. UNIT wBarMenuProc;
  21.  
  22.  
  23.  
  24. INTERFACE
  25.  
  26.  
  27.     USES
  28.         Quickdraw, wBMInterface, wBMGlobals, wBMMiscSubs, OffScreenSubs, wBMScrollSubs;
  29.  
  30.  
  31.     FUNCTION wInitMenus: wMenuBarListHdl;
  32.  
  33.     FUNCTION wGetNewMBar (wp: WindowPtr; wMenuBarID: INTEGER): wMenuBarHandle;
  34.  
  35.     FUNCTION wGetMenuBar (wp: WindowPtr): wMenuBarHandle;
  36.  
  37.     PROCEDURE wSetMenuBar (theMenuBar: wMenuBarHandle; wp: WindowPtr);
  38.  
  39.     PROCEDURE wAddWMB (theMenuBar: wMenuBarHandle);
  40.  
  41.     PROCEDURE wDeleteWMB (wp: WindowPtr);
  42.  
  43.     PROCEDURE wClearMenuBarList (theMenuBarList: wMenuBarListHdl);
  44.  
  45.     PROCEDURE wInsertMenu (theMenuBar: wMenuBarHandle; theMenu: MenuHandle; beforeID: INTEGER);
  46.  
  47.     PROCEDURE wDeleteMenu (theMenuBar: wMenuBarHandle; menuID: INTEGER);
  48.  
  49.     PROCEDURE GetWBMrects (wp: WindowPtr; VAR WBMrect, leftMSArect, rightMSArect: Rect);
  50.  
  51. { PROCEDURE wSetColorMenu (menusID, itemsID: INTEGER);   --   local only }
  52.  
  53.     PROCEDURE wDrawMenuBar (theMenuBar: wMenuBarHandle);
  54.  
  55.     PROCEDURE wScrollMenuBar (theMenuBar: wMenuBarHandle);
  56.  
  57.     PROCEDURE wGetMSA (theMenuBar: wMenuBarHandle);
  58.  
  59.     PROCEDURE wDrawMSA (theMenuBar: wMenuBarHandle);
  60.  
  61.     PROCEDURE wClearMenuBar (theMenuBar: wMenuBarHandle);
  62.  
  63.     FUNCTION wMenuSelect (theMenuBar: wMenuBarHandle; startPt: Point): LONGINT;
  64.  
  65.     FUNCTION wMenuKey (theMenuBar: wMenuBarHandle; ch: char): LONGINT;
  66.  
  67.     PROCEDURE wHiliteMenu (theMenuBar: wMenuBarHandle; menuID: INTEGER);
  68.  
  69.     PROCEDURE wChangeMenuBarSize (wp: WindowPtr; zooming: BOOLEAN);
  70.  
  71.  
  72.  
  73. IMPLEMENTATION
  74.  
  75.  
  76.  
  77.     PROCEDURE MenuDefProc (message: INTEGER; theMenu: MenuHandle; VAR menuRect: Rect; hitPt: Point; VAR whichItem: INTEGER; theProc: ProcPtr);
  78.  
  79.     INLINE
  80.         $205F, $4E90;     { move.l (sp)+,a0 ; jsr (a0) }
  81.  
  82.  
  83.     PROCEDURE MenuDefGlue (message: INTEGER; theMenu: MenuHandle; VAR menuRect: Rect; hitPt: Point; VAR whichItem: INTEGER);
  84.  
  85.         VAR
  86.             mProcState: SignedByte;
  87.  
  88.  
  89.     BEGIN
  90.         LoadResource(theMenu^^.menuProc);
  91.         mProcState := HGetState(theMenu^^.menuProc);
  92.         MoveHHi(theMenu^^.menuProc);
  93.         HLock(theMenu^^.menuProc);
  94.         MenuDefProc(message, theMenu, menuRect, hitPt, whichItem, theMenu^^.menuProc^);
  95.         LoadResource(theMenu^^.menuProc);
  96.         HSetState(theMenu^^.menuProc, mprocState);
  97.     END;   { MenuDefGlue }
  98.  
  99.  
  100.     FUNCTION wInitMenus: wMenuBarListHdl;
  101. { Call immediately after "InitManagers":                                }
  102. {                                                                       }
  103. { Creates a wMenuBarList and quantifies assorted & sordid global parms. }
  104.  
  105.         VAR
  106.             wMBL: wMenuBarListHdl;
  107.  
  108.  
  109.     BEGIN
  110.  
  111.         wMBL := wMenuBarListHdl(NewClearHandle(SizeOf(wMenuBarList)));
  112.         ;
  113.         IF MemError <> noErr THEN
  114.         BEGIN
  115.             wInitMenus := NIL;
  116.             EXIT(wInitMenus);
  117.         END;   { Whoops !! }
  118.  
  119.   { wClearMenuBarList(wMBL);  --  NOT needed here !! }
  120.         wInitMenus := wMBL;
  121.  
  122.   { ++ stuff for BIGees: }
  123.  
  124.         IF sizeFont > normalSize THEN     { From InitBigScreen PROC call on start-up. }
  125.         BEGIN
  126.             betweenTitles := 18;
  127.             aboveBelowItem := 2;
  128.             menuFrame := 2 * frame;
  129.             menuShadow := 2 * shadow;
  130.         END
  131.         ELSE   { small potatoes }
  132.         BEGIN
  133.             betweenTitles := 14;
  134.             aboveBelowItem := 2;
  135.             menuFrame := frame;
  136.             menuShadow := shadow;
  137.         END;   { ELSE }
  138.  
  139.         frameShad := menuFrame + menuShadow;
  140.         scrollPolyDXY := mBarHt DIV 2;
  141.   { Neighboring MENUs share inverted space: }
  142.         invertOverlap := (betweenTitles DIV 2) + 1;
  143.  
  144.     END;   { wInitMenus }
  145.  
  146.  
  147.     FUNCTION wGetNewMBar (wp: WindowPtr; wMenuBarID: INTEGER): wMenuBarHandle;
  148. { Pass wMenuBarID = noMBARrsrc if you wish to start fresh }
  149. { and call wInsertMenu yourself.                          }
  150.  
  151.         CONST
  152.             none = 0;
  153.  
  154.         TYPE
  155.             rMenuBar = RECORD
  156.                     numMenus: INTEGER;
  157.                     menuIDs: ARRAY[0..0] OF INTEGER;
  158.                 END;
  159.             rMenuBarPtr = ^rMenuBar;
  160.             rMenuBarHdl = ^rMenuBarPtr;
  161.  
  162.         VAR
  163.             rMBar: rMenuBarHdl;
  164.             mh: MenuHandle;
  165.             i: INTEGER;
  166.             theWorld: SysEnvRec;
  167.             itDoesMatter: OSErr;
  168.  
  169.  
  170.     BEGIN
  171.  
  172.         wGetNewMBar := NIL;                                { Assume the pits !! }
  173.         ;
  174.         IF wp = NIL THEN
  175.             EXIT(wGetNewMBar);
  176.  
  177.         rMBar := rMenuBarHdl(GetResource('MBAR', wMenuBarID));
  178.  
  179.   { Out with the old Window Menu Bar IF there's one & in with the new: }
  180.         wDeleteWMB(wp);
  181.         ;
  182.         mBar := wMenuBarHandle(NewClearHandle(SizeOf(wMenuBar)));
  183.         IF MemError <> noErr THEN
  184.         BEGIN
  185.             IF rMBar <> NIL THEN
  186.                 ReleaseResource(Handle(rMBar));
  187.             EXIT(wGetNewMBar);
  188.         END;   { Whoops !! }
  189.         mBar^^.titleHilited := noneHilited;
  190.         wSetMenuBar(mBar, wp);
  191.  
  192.         IF (rMBar <> NIL) & (rMBar^^.numMenus > 0) THEN   { & so sue me -- I'm paranoid !! }
  193.         BEGIN
  194.     { Save & restore main Menu Color Table so that GetMenu does NOT change it. }
  195.             IF aMac2 THEN
  196.                 oldMCTable := GetMCInfo;
  197.  
  198.             FOR i := 0 TO (rMBar^^.numMenus - 1) DO
  199.             BEGIN
  200.                 mh := GetMenu(rMBar^^.menuIDs[i]);
  201.                 IF mh <> NIL THEN                             { Paranoid-ville again !! }
  202.                 BEGIN
  203.                     IF i = 0 THEN                                { = Apple Menu }
  204.                     BEGIN
  205.           { Glue fills in all fields EXCEPT systemVersion: }
  206.                         itDoesMatter := SysEnvirons(SysEnvironsVersion, theWorld);
  207.                         IF (itDoesMatter = noErr) & (theWorld.systemVersion < $0700) THEN
  208.                         BEGIN
  209.             { Attached resource file has a 'sicn' here: }
  210.                             SetItemIcon(mh, AboutItem, none);
  211.                             SetItemCmd(mh, AboutItem, char(none));
  212.                         END;
  213.                         AddResMenu(mh, 'DRVR');                     { + DAs }
  214.                     END;   { Apple Menu }
  215.                     wInsertMenu(mBar, mh, atEnd);
  216.                     DetachResource(Handle(mh));    { For calling GetMenu & AddResMenu lots. }
  217.                 END;   { IF mh <> NIL }
  218.             END;   { FOR }
  219.             ;
  220.             ReleaseResource(Handle(rMBar));
  221.  
  222.             IF aMac2 THEN
  223.             BEGIN
  224.                 newMCTable := GetMCInfo;         { Safe on the Stack !! }
  225.                 SetMCInfo(oldMCTable);
  226.                 mbar^^.wMCTable := newMCTable;   { Save for drawing & selecting. }
  227.             END;   { IF aMac2}
  228.         END;   { IF a rMBar }
  229.  
  230.         wGetNewMBar := mBar;
  231.  
  232.     END;   { wGetNewMBar }
  233.  
  234.  
  235.     FUNCTION wGetMenuBar (wp: WindowPtr): wMenuBarHandle;
  236.  
  237.         VAR
  238.             i: INTEGER;
  239.  
  240.  
  241.     BEGIN
  242.  
  243.         found := false;
  244.         i := 0;
  245.         ;
  246.         wGetMenuBar := NIL;
  247.         IF mBarList = NIL THEN
  248.             EXIT(wGetMenuBar);
  249.  
  250.         WITH mBarList^^ DO
  251.         BEGIN
  252.             IF numWindows > 0 THEN
  253.                 WHILE (NOT found) & (i < numWindows) DO
  254.                     IF WMBars[i]^^.wp = wp THEN
  255.                         found := true
  256.                     ELSE
  257.                         i := i + 1                   { End of WHILE }
  258.  
  259.             ELSE   { zip windows }
  260.                 ;
  261.  
  262.             IF found THEN
  263.                 wGetMenuBar := WMBars[i];
  264.         END;   { WITH }
  265.  
  266.     END;   { wGetMenuBar }
  267.  
  268.  
  269.     PROCEDURE wSetMenuBar (theMenuBar: wMenuBarHandle; wp: WindowPtr);
  270.  
  271.  
  272.     BEGIN
  273.         theMenuBar^^.wp := wp;               { Simple, aint it ?!!? }
  274.     END;   { wSetMenuBar }
  275.  
  276.  
  277.     PROCEDURE wAddWMB (theMenuBar: wMenuBarHandle);
  278. { For example:                              }
  279. {                                           }
  280. {   windPtr := GetNewWindow();              }
  281. {   menuBar := wGetNewMBar(windPtr, barID); }
  282. {   IF menuBar <> NIL THEN                  }
  283. {    wAddWMB(menuBar);                      }
  284.  
  285.         VAR
  286.             i: INTEGER;
  287.  
  288.  
  289.     BEGIN
  290.  
  291.         newBarListSize := SizeOf(wMenuBarList) + (mBarList^^.numWindows + 1) * 4;
  292.         IF newBarListSize > GetHandleSize(Handle(mBarList)) THEN
  293.             IF MemError = noErr THEN
  294.                 SetHandleSize(Handle(mBarList), newBarListSize);
  295.  
  296.         IF MemError = noErr THEN
  297.             WITH mBarList^^ DO
  298.             BEGIN
  299.                 WMBars[numWindows] := theMenuBar;
  300.                 numWindows := numWindows + 1
  301.             END;   { WITH }
  302.  
  303.     END;   { wAddWMB }
  304.  
  305.  
  306.     PROCEDURE wDeleteWMB (wp: WindowPtr);
  307.  
  308.         VAR
  309.             i, j: INTEGER;
  310.  
  311.  
  312.     BEGIN
  313.  
  314.         found := false;
  315.         i := 0;
  316.  
  317.         IF mBarList^^.numWindows > 0 THEN
  318.         BEGIN
  319.  
  320.             WHILE (NOT found) & (i < mBarList^^.numWindows) DO
  321.                 IF mBarList^^.WMBars[i]^^.wp = wp THEN
  322.                     found := true
  323.                 ELSE
  324.                     i := i + 1;                                { End of WHILE }
  325.  
  326.             IF found THEN
  327.             BEGIN
  328.                 wClearMenuBar(mBarList^^.WMBars[i]);
  329.                 DisposHandle(Handle(mBarList^^.WMBars[i]));
  330.                 IF i <> (mBarList^^.numWindows - 1) THEN   { Not the last one in the List. }
  331.                     FOR j := (i + 1) TO (mBarList^^.numWindows - 1) DO
  332.                         mBarList^^.WMBars[j - 1] := mBarList^^.WMBars[j]
  333.                 ELSE           { Delete the last one.  Already done, so nada required here. }
  334.                     ;
  335.                 mBarList^^.numWindows := mBarList^^.numWindows - 1;
  336.                 newBarListSize := GetHandleSize(Handle(mBarList)) - 4;
  337.                 IF MemError = noErr THEN
  338.                     SetHandleSize(Handle(mBarList), newBarListSize);
  339.             END;   { IF found }
  340.  
  341.         END   { IF numWindows >0 }
  342.  
  343.         ELSE   { zip windows }
  344.             ;
  345.  
  346.     END;   { wDeleteWMB }
  347.  
  348.  
  349.     PROCEDURE wClearMenuBarList (theMenuBarList: wMenuBarListHdl);
  350. { For now, I do NOT use the passed parm because it's a global.  }
  351. { This may change in the future, however.                       }
  352.  
  353.         CONST
  354.             WindowListLoc = $9D6;                { 1st window in linked list. }
  355.  
  356.         VAR
  357.             window: WindowPeek;
  358.  
  359.  
  360.     BEGIN
  361.  
  362.         window := WindowPeek(longPtr(WindowListLoc));
  363.         WHILE window <> NIL DO
  364.         BEGIN
  365.             wDeleteWMB(WindowPtr(window));
  366.             window := window^.nextWindow;
  367.         END;   { WHILE }
  368.  
  369.   { The following has already happened after execution of above WHILE loop: }
  370.   {                                                                         }
  371.   { theMenuBarList^^.numWindows := 0;                                       }
  372.   { SetHandleSize(Handle(theMenuBarList), SizeOf(wMenuBarList));            }
  373.  
  374.     END;   { wClearMenuBarList }
  375.  
  376.  
  377.     FUNCTION IncreaseSize (theMenuBar: wMenuBarHandle): OSErr;
  378.  
  379.         VAR
  380.             hState: SignedByte;
  381.  
  382.  
  383.     BEGIN
  384.         newWMBSize := SizeOf(wMenuBar) + (theMenuBar^^.numMenus + 1) * SizeOf(wMenuRec);
  385.         IF newWMBSize > GetHandleSize(Handle(theMenuBar)) THEN
  386.             IF MemError = noErr THEN
  387.             BEGIN
  388.                 hState := HGetState(Handle(theMenuBar));
  389.                 HUnlock(Handle(theMenuBar));
  390.                 SetHandleSize(Handle(theMenuBar), newWMBSize);
  391.       { Just in case entry state is locked: }
  392.                 MoveHHi(Handle(theMenuBar));
  393.                 HSetState(Handle(theMenuBar), hState);
  394.             END;
  395.         ;
  396.         IncreaseSize := MemError;
  397.     END;   { IncreaseSize }
  398.  
  399.  
  400.     FUNCTION DecreaseSize (theMenuBar: wMenuBarHandle): OSErr;
  401.  
  402.         VAR
  403.             hState: SignedByte;
  404.  
  405.  
  406.     BEGIN
  407.         newWMBSize := SizeOf(wMenuBar) + (theMenuBar^^.numMenus - 1) * SizeOf(wMenuRec);
  408.         IF newWMBSize < GetHandleSize(Handle(theMenuBar)) THEN
  409.             IF MemError = noErr THEN
  410.             BEGIN
  411.                 hState := HGetState(Handle(theMenuBar));
  412.                 HUnlock(Handle(theMenuBar));
  413.                 SetHandleSize(Handle(theMenuBar), newWMBSize);
  414.                 MoveHHi(Handle(theMenuBar));
  415.                 HSetState(Handle(theMenuBar), hState);
  416.             END;
  417.         ;
  418.         DecreaseSize := MemError;
  419.     END;   { DecreaseSize }
  420.  
  421.  
  422.     FUNCTION GetTitleWidth (theMenu: MenuHandle): INTEGER;
  423.  
  424.         VAR
  425.             oldTxSize, oldTxFont, oldTxMode: INTEGER;
  426.             oldTxStyle: Style;
  427.  
  428.  
  429.     BEGIN
  430.         oldTxFont := thePort^.txFont;
  431.         oldTxSize := thePort^.txSize;
  432.         oldTxStyle := thePort^.txFace;
  433.         TextFont(systemFont);
  434.         myTextSize(sizeFont);
  435.         TextFace([]);
  436.         ;
  437.         GetTitleWidth := StringWidth(theMenu^^.menuData);
  438.         ;
  439.         TextFont(oldTxFont);
  440.         myTextSize(oldTxSize);
  441.         TextFace(oldTxStyle);
  442.     END;   { GetTitleWidth }
  443.  
  444.  
  445.     FUNCTION GetItemIconSize (theMenu: MenuHandle; item: INTEGER): INTEGER;
  446.  
  447.         CONST
  448.             reducedIconCmd = $1D;
  449.             smallIconCmd = $1E;
  450.  
  451.         VAR
  452.             iconNbr: Byte;
  453.             sizeIcon: INTEGER;
  454.             theCICN: CIconHandle;
  455.             cmdChar: char;
  456.  
  457.  
  458.     BEGIN
  459.  
  460.         GetItemIcon(theMenu, item, iconNbr);
  461.         IF iconNbr = 0 THEN
  462.             sizeIcon := 0
  463.         ELSE
  464.         BEGIN
  465.             IF aMac2 THEN
  466.             BEGIN
  467.                 theCICN := GetCIcon(iconNbr + 256);
  468.                 IF theCICN <> NIL THEN
  469.                 BEGIN
  470.                     WITH theCICN^^.iconPMap.bounds DO
  471.                         sizeIcon := bottom - top;
  472.                     DisposCIcon(theCICN);
  473.                 END
  474.                 ELSE   { no cicn }
  475.                     sizeIcon := 32;
  476.             END   { aMac2 }
  477.             ELSE
  478.                 sizeIcon := 32;
  479.  
  480.             GetItemCmd(theMenu, item, cmdChar);
  481.             IF (cmdChar = chr(reducedIconCmd)) | (cmdChar = chr(smallIconCmd)) THEN
  482.                 sizeIcon := sizeIcon DIV 2;
  483.         END;   { Has either an ICON, a CICN, a reduced icon or a SICN }
  484.  
  485.         GetItemIconSize := sizeIcon;
  486.  
  487.     END;   { GetItemIconSize }
  488.  
  489.  
  490.     PROCEDURE wInsertMenu (theMenuBar: wMenuBarHandle; theMenu: MenuHandle; beforeID: INTEGER);
  491. { Insert a Menu into a defined wMenuBar: }
  492.  
  493.         VAR
  494.             hierID, index, i, j: INTEGER;
  495.             found, enabled: BOOLEAN;
  496.             parentMenuHdl: MenuHandle;
  497.             oldPort: GrafPtr;
  498.             cmdChar, parentMark: char;
  499.             parentItemRect, parentFrameRect: Rect;
  500.             currentHeight, prevHeight, sizeIcon: INTEGER;
  501.  
  502.  
  503.     BEGIN
  504.  
  505.         IF beforeID = atEnd THEN
  506.         BEGIN
  507.  
  508.             i := 0;
  509.             WHILE (i < theMenuBar^^.numMenus) & (theMenuBar^^.wMenus[i].menuType = regMenu) DO
  510.                 i := i + 1;
  511.  
  512.             IF i < theMenuBar^^.numMenus THEN
  513.     { Insert after end of regular portion of Window Menu Bar, }
  514.     { which occurs just prior to the Hierarchical portion.    }
  515.             BEGIN
  516.                 wInsertMenu(theMenuBar, theMenu, theMenuBar^^.wMenus[i].mh^^.menuID);
  517.                 EXIT(wInsertMenu);
  518.             END
  519.             ELSE
  520.             BEGIN
  521.                 IF IncreaseSize(theMenuBar) <> noErr THEN
  522.                     EXIT(wInsertMenu);
  523.                 titleWidth := GetTitleWidth(theMenu);
  524.             END;   { ELSE: i = numMenus }
  525.  
  526.         END   { beforeID = atEnd }
  527.  
  528.         ELSE IF beforeID = hierMenu THEN
  529.         BEGIN
  530.  
  531.             hierID := theMenu^^.menuID;
  532.             i := 0;
  533.             found := false;
  534.             ;
  535.             WHILE (i < theMenuBar^^.numMenus) & NOT found DO   { Scan entire wMenuBar. }
  536.             BEGIN
  537.                 parentMenuHdl := theMenuBar^^.wMenus[i].mh;
  538.                 FOR j := 1 TO CountMItems(parentMenuHdl) DO       { Scan each menu. }
  539.                 BEGIN
  540.                     GetItemCmd(parentMenuHdl, j, cmdChar);
  541.                     IF cmdChar = char(hMenuCmd) THEN
  542.                     BEGIN
  543.                         GetItemMark(parentMenuHdl, j, parentMark);
  544.                         IF ord(parentMark) = hierID THEN
  545.                         BEGIN
  546.                             found := true;
  547.                             Leave;   { FOR loop }
  548.                         END;   { IF ord() }
  549.                     END;   { Hierarchical Menu }
  550.                 END;   { FOR }
  551.  
  552.                 i := i + 1;                       { IF found, i = correct # plus 1. }
  553.             END;   { WHILE }
  554.  
  555.             IF found THEN                      { ... is it enabled ??? }
  556.                 IF j < 32 THEN
  557.                     enabled := BitTst(@theMenuBar^^.wMenus[i - 1].mh^^.enableFlags, menuTitleBit - j)
  558.                 ELSE
  559.                     enabled := true;                { Items 32 & beyond. }
  560.  
  561.             IF found & enabled & (IncreaseSize(theMenuBar) = noErr) THEN
  562.             BEGIN
  563.                 WITH theMenuBar^^, wMenus[numMenus] DO
  564.                 BEGIN
  565.  
  566.                     mh := theMenu;                   { Place at end = Hierarchical portion. }
  567.                     menuType := hierMenu;
  568.                     parentID := parentMenuHdl^^.menuID;
  569.         { These fields are filled-in later by wMenuSelect   }
  570.         { for both Hierarchical and Regular menus:          }
  571.         {                                                   }
  572.         {   menuParentRgn, cumParentRgn and MenuDownOSHdl   }
  573.         {                                                   }
  574.         { You'll notice that I ignore these fields when     }
  575.         { inserting and deleting a Regular menu because     }
  576.         { Hierarchical menus are inserted AFTER all Regular }
  577.         { menus and are deleted immediately after use.      }
  578.  
  579.                 END;   { WITH theMenuBar^^, wMenus[numMenus] }
  580.  
  581.       { titleRect = parent item's rect.               }
  582.       {                                               }
  583.       { For starters, setup left & right coordinates: }
  584.  
  585.                 WITH parentItemRect DO
  586.                 BEGIN
  587.                     WITH theMenuBar^^.wMenus[i - 1] DO   { [i-1] belongs to parentMenuHdl. }
  588.                         IF menuType = regMenu THEN
  589.                             left := titleRect.left + menuFrame
  590.                         ELSE
  591.                             left := titleRect.right - 4 * menuFrame + menuFrame;
  592.                     CalcMenuSize(parentMenuHdl);
  593.                     right := left + parentMenuHdl^^.menuWidth;
  594.                 END;   { WITH parentItemRect }
  595.  
  596.                 WITH theMenuBar^^.wMenus[i - 1] DO
  597.                     IF menuType = regMenu THEN
  598.                         currentHeight := titleRect.bottom + menuFrame
  599.                     ELSE
  600.                         currentHeight := titleRect.top + menuFrame;
  601.  
  602.                 FOR index := 1 TO j DO
  603.                 BEGIN
  604.                     prevHeight := currentHeight;
  605.                     sizeIcon := GetItemIconSize(parentMenuHdl, index);
  606.                     currentHeight := currentHeight + aboveBelowItem + Max(sizeFont, sizeIcon) + aboveBelowItem;
  607.                 END;   { FOR }
  608.  
  609.                 WITH parentItemRect DO          { Complete the other two dimensions. }
  610.                 BEGIN
  611.                     top := prevHeight;
  612.                     bottom := currentHeight;
  613.                 END;   { WITH parentItemRect }
  614.  
  615.                 WITH theMenuBar^^, wMenus[i - 1] DO
  616.                 BEGIN
  617.                     parentFrameRect := parentItemRect;     { Change ONLY right & left coords ... }
  618.                     WITH parentFrameRect DO
  619.                     BEGIN
  620.                         left := left - menuFrame;
  621.                         right := right + menuFrame + menuShadow;
  622.                     END;   { WITH parentFrameRect }
  623.  
  624.                     GetPort(oldPort);
  625.         { ----- }
  626.                     SetPort(wp);
  627.                     LocalGlobal(parentFrameRect);
  628.                     WITH gScreen DO                         { GrayRgn's rgnBBox - global coords. }
  629.                     BEGIN
  630.                         IF parentFrameRect.right > right - 2 * menuFrame THEN  { Shift left. }
  631.                             IF menuType = regMenu THEN
  632.                                 OffsetRect(parentFrameRect, right - 2 * menuFrame - parentFrameRect.right, 0)
  633.                             ELSE
  634.                                 OffsetRect(parentFrameRect, -(titleRect.right - titleRect.left - 8 * menuFrame + (parentFrameRect.right - parentFrameRect.left)), 0);
  635.                         ;
  636.                         IF parentFrameRect.left < left + 2 * menuFrame THEN    { Shift right. }
  637.                             OffsetRect(parentFrameRect, left + 2 * menuFrame - parentFrameRect.left, 0);
  638.                     END;   { WITH gScreen }
  639.                     GlobalLocal(parentFrameRect);  { Back to local window coordinates. }
  640.         { ----- }
  641.                     SetPort(oldPort);
  642.  
  643.                     parentItemRect := parentFrameRect;
  644.                     WITH parentItemRect DO
  645.                     BEGIN
  646.                         left := left + menuFrame;
  647.                         right := right - menuFrame - menuShadow;
  648.                     END;
  649.                     ;
  650.         { [numMenus] belongs to inserted sub-Menu: }
  651.                     wMenus[numMenus].titleRect := parentItemRect;
  652.                     numMenus := numMenus + 1;
  653.                 END;   { WITH theMenuBar^^, wMenus[i - 1] }
  654.  
  655.             END;   { IF found & enabled & IncreaseSize }
  656.  
  657.             EXIT(wInsertMenu);
  658.  
  659.         END   { beforeID = hierMenu }
  660.  
  661.         ELSE   { Smack in the middle somewhere !! }
  662.         BEGIN
  663.  
  664.             IF IncreaseSize(theMenuBar) <> noErr THEN
  665.                 EXIT(wInsertMenu);
  666.  
  667.             titleWidth := GetTitleWidth(theMenu);
  668.  
  669.             WITH theMenuBar^^ DO
  670.             BEGIN
  671.  
  672.                 i := 0;
  673.                 WHILE (i < numMenus) & (wMenus[i].mh^^.menuID <> beforeID) DO
  674.                     i := i + 1;
  675.                 ;
  676.                 IF i <> numMenus THEN
  677.                 BEGIN
  678.                     FOR j := numMenus DOWNTO (i + 1) DO
  679.                     BEGIN
  680.                         wMenus[j].mh := wMenus[j - 1].mh;
  681.                         wMenus[j].menuType := wMenus[j - 1].menuType;
  682.                         wMenus[j].parentID := wMenus[j - 1].parentID;
  683.                 { Overkill just to copy top & bottom ... }
  684.                         wMenus[j].titleRect := wMenus[j - 1].titleRect;
  685.                 { ... now, adjust right & left if a regular Menu. }
  686.                         IF wMenus[j].menuType = regMenu THEN
  687.                             OffsetRect(wMenus[j].titleRect, titleWidth + betweenTitles, 0);
  688.                     END;   { FOR j := numMenus DOWNTO (i + 1) }
  689.                 END;   { IF i <> numMenus }
  690.  
  691.             END;   { WITH }
  692.  
  693.         END;   { in middle }
  694.  
  695.   { Some wierd arithmetic ... }
  696.  
  697.         WITH theMenuBar^^, wMenus[i].titleRect DO
  698.         BEGIN
  699.  
  700.             top := wp^.portRect.top;
  701.             ;
  702.             bottom := top + mBarHt - menuFrame;
  703.             ;
  704.             left := wp^.portRect.left;
  705.             IF i = 0 THEN   { Make room for Menu Scroll Activator  --  see "wDrawMSA": }
  706.                 left := left + 2 * scrollPolyDXY + menuFrame + betweenTitles - invertOverlap
  707.             ELSE
  708.                 left := left + wMenus[i - 1].titleRect.right - invertOverlap + betweenTitles - invertOverlap;
  709.             ;
  710.             right := left + invertOverlap + titleWidth + invertOverlap;
  711.  
  712.             IF numMenus = 0 THEN                    { 1st call to wInsertMenu. }
  713.                 barLength := betweenTitles + titleWidth + betweenTitles
  714.             ELSE
  715.                 barLength := barLength + titleWidth + betweenTitles;
  716.  
  717.             wMenus[i].mh := theMenu;
  718.             wMenus[i].menuType := regMenu;
  719.             wMenus[i].parentID := mainMenu;
  720.             numMenus := numMenus + 1;
  721.  
  722.         END;   { WITH }
  723.  
  724.     END;   { wInsertMenu }
  725.  
  726.  
  727.     PROCEDURE wDeleteMenu (theMenuBar: wMenuBarHandle; menuID: INTEGER);
  728.  
  729.         VAR
  730.             i, j: INTEGER;
  731.  
  732.  
  733.     BEGIN
  734.  
  735.         i := 0;
  736.         WITH theMenuBar^^ DO
  737.             WHILE (i < numMenus) & (wMenus[i].mh^^.menuID <> menuID) DO
  738.                 i := i + 1;                    { End of 1st WITH }
  739.         ;
  740.         IF i <> theMenuBar^^.numMenus THEN
  741.         BEGIN
  742.             IF theMenuBar^^.wMenus[i].menuType = regMenu THEN
  743.                 titleWidth := GetTitleWidth(theMenuBar^^.wMenus[i].mh);
  744.  
  745.             WITH theMenuBar^^ DO
  746.             BEGIN
  747.  
  748.                 IF wMenus[i].menuType = regMenu THEN
  749.                     IF numMenus = 1 THEN        { Soon to be zero. }
  750.                         barLength := 0
  751.                     ELSE
  752.                         barLength := barLength - titleWidth - betweenTitles;
  753.  
  754.                 FOR j := (i + 1) TO (numMenus - 1) DO
  755.                 BEGIN
  756.                     wMenus[j - 1].mh := wMenus[j].mh;
  757.                     wMenus[j - 1].menuType := wMenus[j].menuType;
  758.                     wMenus[j - 1].parentID := wMenus[j].parentID;
  759.                     wMenus[j - 1].titleRect := wMenus[j].titleRect;
  760.                     IF wMenus[j - 1].menuType = regMenu THEN
  761.                         OffsetRect(wMenus[j - 1].titleRect, -(titleWidth + betweenTitles), 0);
  762.                 END;   { FOR j := (i + 1) TO (numMenus - 1) }
  763.  
  764.             END;   { 2nd WITH }
  765.  
  766.             IF DecreaseSize(theMenuBar) = noErr THEN
  767.                 ;
  768.             theMenuBar^^.numMenus := theMenuBar^^.numMenus - 1;
  769.         END;   { IF i <> theMenuBar^^.numMenus }
  770.  
  771.     END;   { wDeleteMenu }
  772.  
  773.  
  774.     PROCEDURE GetWBMrects (wp: WindowPtr; VAR WBMrect, leftMSArect, rightMSArect: Rect);
  775.  
  776.         PROCEDURE ZeroRect (VAR r: Rect);
  777.  
  778.         BEGIN
  779.  
  780.             WITH r DO
  781.             BEGIN
  782.                 top := 0;
  783.                 left := 0;
  784.                 bottom := 0;
  785.                 right := 0;
  786.             END;   { WITH }
  787.  
  788.         END;   { ZeroRect }
  789.  
  790.  
  791.     BEGIN   { GetWBMrects }
  792.  
  793.         IF wGetMenuBar(wp) <> NIL THEN
  794.         BEGIN
  795.  
  796.             windType := GetWindowType(wp);   { + quantifies "hasGrowIcon" for update Event. }
  797.             WBMrect := wp^.portRect;
  798.             WITH WBMrect DO
  799.             BEGIN
  800.                 IF hasGrowIcon THEN
  801.                     right := right - (scrollWidth - frame);
  802.                 bottom := top + mBarHt;
  803.             END;
  804.  
  805.             leftMSArect := WBMrect;
  806.             WITH leftMSArect DO
  807.                 right := left + 2 * scrollPolyDXY + menuFrame;
  808.  
  809.             rightMSArect := WBMrect;
  810.             WITH rightMSArect DO
  811.                 left := right - 2 * scrollPolyDXY - menuFrame;
  812.  
  813.         END   { window has a Window Bar Menu }
  814.         ELSE
  815.         BEGIN
  816.             ZeroRect(WBMrect);
  817.             ZeroRect(leftMSArect);
  818.             ZeroRect(rightMSArect);
  819.         END;   { ELSE }
  820.  
  821.         dynamicBalloons[0].dynamicStrID := 128;
  822.         IF windType = rDocProc THEN
  823.             dynamicBalloons[0].dynamicStrIndex := 3
  824.         ELSE
  825.             dynamicBalloons[0].dynamicStrIndex := 6;
  826.         dynamicBalloons[0].dynamicR := leftMSArect;
  827.         ;
  828.         dynamicBalloons[1].dynamicStrID := 128;
  829.         IF windType = rDocProc THEN
  830.             dynamicBalloons[1].dynamicStrIndex := 2
  831.         ELSE
  832.             dynamicBalloons[1].dynamicStrIndex := 5;
  833.         dynamicBalloons[1].dynamicR := WBMrect;
  834.         InsetRect(dynamicBalloons[1].dynamicR, leftMSArect.right, 0);   { Between MSAs. }
  835.         ;
  836.         dynamicBalloons[2].dynamicStrID := 128;
  837.         IF windType = rDocProc THEN
  838.             dynamicBalloons[2].dynamicStrIndex := 4
  839.         ELSE
  840.             dynamicBalloons[2].dynamicStrIndex := 7;
  841.         dynamicBalloons[2].dynamicR := rightMSArect;
  842.  
  843.     END;   { GetWBMrects }
  844.  
  845.  
  846.     PROCEDURE GetColors;
  847.  
  848.     BEGIN
  849.  
  850.         IF aMac2 THEN
  851.         BEGIN
  852.             GetBackColor(oldBackColor);
  853.             GetForeColor(oldForeColor);
  854.         END;   { IF }
  855.  
  856.     END;   { GetColors }
  857.  
  858.  
  859.     PROCEDURE RestoreColors;
  860.  
  861.     BEGIN
  862.  
  863.         IF aMac2 THEN
  864.         BEGIN
  865.             RGBBackColor(oldBackColor);
  866.             RGBForeColor(oldForeColor);
  867.         END;   { IF }
  868.  
  869.     END;   { RestoreColors }
  870.  
  871.  
  872.     PROCEDURE wSetColorMenu (menusID, itemsID: INTEGER);
  873. { Without redefining Apple's built-in MenuDefProc, we're restricting }
  874. { ourselves to ALL Item text (including the mark & CMD-key) being    }
  875. { the same color and ditto for the background color of ALL Items.    }
  876.  
  877.         VAR
  878.             MCTBEntry: MCEntryPtr;
  879.     { What we actually got back from GetMCTBEntry       }
  880.     { compared with what we asked for, the latter       }
  881.     { being the original parms passed to wSetColorMenu: }
  882.             returnedMenuID, returnedMenuItem: INTEGER;
  883.  
  884.  
  885.         FUNCTION GetMCTBEntry (VAR menuID, itemID: INTEGER): MCEntryPtr;
  886.  
  887.             VAR
  888.                 mctbEntryPtr: MCEntryPtr;
  889.  
  890.  
  891.         BEGIN
  892.  
  893.             GetMCTBEntry := NIL;                 { NOT very optimistic, are we ?!!? }
  894.  
  895.             mctbEntryPtr := GetMCEntry(menuID, itemID);
  896.  
  897.             IF mctbEntryPtr = NIL THEN
  898.     { Could NOT find what we asked for, so recurse UP the chain:               }
  899.     {                                                                          }
  900.     {   if no specified Item entry, then look for Title entry                  }
  901.     {   if no asked-for Title entry, then look for MenuBar entry               }
  902.     {   if no specified MenuBar entry, then our 'mctb' resource is NOT correct }
  903.             BEGIN
  904.  
  905.                 IF (menuID <> mceMenuBar) & (itemID <> mceMenuTitle) THEN
  906.                 BEGIN     { Asked for item }
  907.                     itemID := mceMenuTitle;
  908.                     GetMCTBEntry := GetMCTBEntry(menuID, itemID);
  909.                 END
  910.                 ELSE IF (menuID <> mceMenuBar) & (itemID = mceMenuTitle) THEN
  911.                 BEGIN     { Asked for title }
  912.                     menuID := mceMenuBar;
  913.                     itemID := mceMenuBar;
  914.                     GetMCTBEntry := GetMCTBEntry(menuID, itemID);
  915.                 END
  916.                 ELSE IF (menuID = mceMenuBar) & (itemID = mceMenuBar) THEN
  917.                     ;   { Ran out of steam !!! }
  918.  
  919.             END
  920.             ELSE
  921.                 GetMCTBEntry := mctbEntryPtr;
  922.  
  923.         END;   { GetMCTBEntry }
  924.  
  925.  
  926.     BEGIN   { wSetColorMenu }
  927.  
  928.         IF NOT aMac2 THEN
  929.             EXIT(wSetColorMenu);
  930.  
  931.         returnedMenuID := menusID;      { VARed ... what we actually get }
  932.         returnedMenuItem := itemsID;    {   back from GetMCTBEntry.      }
  933.         ;
  934.         MCTBEntry := GetMCTBEntry(returnedMenuID, returnedMenuItem);
  935.         IF MCTBEntry = NIL THEN
  936.             EXIT(wSetColorMenu);
  937.  
  938.         WITH MCTBEntry^ DO
  939.  
  940.             IF (returnedMenuID <> mceMenuBar) & (returnedMenuItem <> mceMenuTitle) THEN
  941.             BEGIN                        { Asked for AND got a Menu Item. }
  942.                 RGBBackColor(mctRGB4);
  943.                 RGBForeColor(mctRGB2);
  944.             END   { an Item element}
  945.  
  946.             ELSE IF (returnedMenuID <> mceMenuBar) & (returnedMenuItem = mceMenuTitle) THEN
  947.             BEGIN
  948.                 RGBBackColor(mctRGB4);
  949.                 IF itemsID = mceMenuTitle THEN         { Asked for AND got a Menu Title. }
  950.                     RGBForeColor(mctRGB1)
  951.                 ELSE                       { Asked for an Item, recursed to a Title. }
  952.                     RGBForeColor(mctRGB3);
  953.             END   { a Title element }
  954.  
  955.             ELSE IF (returnedMenuID = mceMenuBar) & (returnedMenuItem = mceMenuBar) THEN
  956.             BEGIN
  957.       { Here, if you ask for the MenuBar entry, I assume you're just interested }
  958.       { in the background color because you're coloring the overall MenuBar via }
  959.       { _EraseRect.  If you're really interested in the background color of the }
  960.       { pulled-down Menu, then ask for a Menu Title or a Menu Item entry.       }
  961.                 IF menusID = mceMenuBar THEN           { Got what we asked for !! }
  962.                     RGBBackColor(mctRGB4)
  963.                 ELSE IF itemsID = mceMenuTitle THEN    { Asked for a Title, recursed to MenuBar. }
  964.                 BEGIN
  965.                     RGBBackColor(mctRGB2);
  966.                     RGBForeColor(mctRGB1);
  967.                 END
  968.                 ELSE                       { Asked for an Item, recursed TWICE to MenuBar. }
  969.                 BEGIN
  970.                     RGBBackColor(mctRGB2);
  971.                     RGBForeColor(mctRGB3);
  972.                 END
  973.             END;   { got back a MenuBar element}
  974.              { End of WITH }
  975.  
  976.     END;   { wSetColorMenu }
  977.  
  978.  
  979.     PROCEDURE wDrawMenuBar (theMenuBar: wMenuBarHandle);
  980. { Draw a wMenuBar with appropriate highlighting: }
  981.  
  982.         LABEL
  983.             100, 200;
  984.  
  985.         VAR
  986.             active: BOOLEAN;
  987.             y0, i: INTEGER;
  988.             lsWBMrect, offBarRect, titleR, visDrawingRect: Rect;
  989.             titleRgn: RgnHandle;
  990.     { Keep safe on Stack to avoid Memory Manager blues ... }
  991.             safeTitle: Str255;
  992.  
  993.  
  994.     BEGIN
  995.  
  996.         IF theMenuBar^^.numMenus = 0 THEN        { Nada !! }
  997.             EXIT(wDrawMenuBar);
  998.  
  999.         mbHState := HGetState(Handle(theMenuBar));
  1000.         MoveHHi(Handle(theMenuBar));
  1001.         HLock(Handle(theMenuBar));                { ... because some TRAPs called inside }
  1002.                                               {     the WITH block move memory.      }
  1003.         GetPort(oldPort);
  1004.         SetPort(theMenuBar^^.wp);
  1005.         oldClip := NewRgn;
  1006.         GetClip(oldClip);
  1007.         ;
  1008.         GetColors;
  1009.         IF aMac2 THEN
  1010.         BEGIN
  1011.             oldMCTable := GetMCInfo;
  1012.             SetMCInfo(theMenuBar^^.wMCTable);
  1013.         END;   { IF aMac2 }
  1014.  
  1015.         lsWBMrect := WBMrect;                     { GetWBMrects already called by wDrawMSA. }
  1016.         LocalGlobal(lsWBMrect);
  1017.  
  1018.   { Local window coordinates are input to & local screen }
  1019.   { coordinates are returned from CreateOffScreen:       }
  1020.  
  1021.         WITH theMenuBar^^ DO
  1022.         BEGIN
  1023.  
  1024.             active := (ORD(WindowPeek(wp)^.hilited) <> 0);
  1025.  
  1026.     { offBarRect may end up being wider than window's portRect. }
  1027.             WITH offBarRect DO
  1028.             BEGIN
  1029.                 top := WBMrect.top;
  1030.                 bottom := WBMrect.bottom - menuFrame;
  1031.                 left := leftMSArect.right;
  1032.                 right := left + barLength;
  1033.                 IF right < rightMSArect.left THEN
  1034.                     right := rightMSArect.left;
  1035.             END;   { WITH offBarRect }
  1036.  
  1037.             IF barOSHdl <> NIL THEN
  1038.             BEGIN
  1039.                 LocalGlobal(offBarRect);
  1040.                 WITH lScreen DO                      { _GlobalToLocal }
  1041.                     OffsetRect(offBarRect, left, top);
  1042.                 GOTO 100;
  1043.             END;   { Still there }
  1044.  
  1045.             barOSHdl := CreateOffScreen(offBarRect);
  1046.             IF (QuickStrip(Ptr(barOSHdl)) = NIL) | (barOSHdl^^.CreateOffScreenError <> noErr) THEN
  1047.                 GOTO 200;
  1048.  
  1049.     { ELSE draw into off-screen Port as follows: }
  1050.  
  1051.             TextFont(systemFont);
  1052.             myTextSize(sizeFont);
  1053.             TextFace([]);
  1054.             TextMode(srcOr);
  1055.  
  1056.     { We canNOT call _GlobalToLocal here because we've changed the portBits.bounds }
  1057.     { rectangle of our off-screen port within "CreateOffScreen".                   }
  1058.  
  1059.             WITH lScreen DO                                  { Bounds BEFORE change. }
  1060.                 OffsetRect(lsWBMrect, left, top);
  1061.             ;
  1062.             ClipRect(offBarRect);
  1063.             wSetColorMenu(mceMenuBar, mceMenuBar);
  1064.             EraseRect(offBarRect);                            { Eliminate all stray matter. }
  1065.  
  1066.             y0 := (mBarHt - menuFrame - sizeFont) DIV 2;
  1067.             ;
  1068.             FOR i := 0 TO (numMenus - 1) DO
  1069.             BEGIN
  1070.  
  1071.                 IF wMenus[i].menuType = hierMenu THEN
  1072.                     Cycle;
  1073.  
  1074.                 titleR := wMenus[i].titleRect;
  1075.           { Convert to local screen coordinates: }
  1076.                 OffsetRect(titleR, lsWBMrect.left, lsWBMrect.top);
  1077.           { Eliminate the overshoot placed there to invert the title, }
  1078.           { because all we wish to do is to draw the title string:    }
  1079.                 InsetRect(titleR, invertOverlap, 0);
  1080.                 ;
  1081.                 MoveTo(titleR.left, titleR.bottom - y0);
  1082.                 wSetColorMenu(wMenus[i].mh^^.menuID, mceMenuTitle);
  1083.                 safeTitle := wMenus[i].mh^^.menuData;
  1084.                 DrawString(safeTitle);
  1085.  
  1086.       { Gray-out disabled Menu titles ONLY if window is active. }
  1087.       { We dim the whole Window Bar Menu below if window isn't. }
  1088.       { The latter allows for CMD-dragging the window.          }
  1089.  
  1090.                 IF active & NOT BitTst(@wMenus[i].mh^^.enableFlags, menuTitleBit) THEN
  1091.                 BEGIN
  1092.                     titleRgn := NewRgn;
  1093.                     RectRgn(titleRgn, titleR);
  1094.                     DimRgn(titleRgn);
  1095.                     DisposeRgn(titleRgn);
  1096.                 END;   { Gray-out disabled title }
  1097.  
  1098.             END;   { FOR ... drawing off-screen }
  1099. 100:
  1100.             ToOnScreen(barOSHdl);                             { Back to "Square 1". }
  1101.  
  1102.             WITH barOSHdl^^ DO
  1103.             BEGIN
  1104.                 visDrawingRect := drawingRect;
  1105.  
  1106.                 ClipRect(drawingRect);
  1107.  
  1108.                 BackColor(whiteColor);                          { So funny colorization }
  1109.                 ForeColor(blackColor);                          {   does NOT happen !!  }
  1110.                 ;
  1111.                 WITH visDrawingRect DO              { Adjust if overlapping right MSA. }
  1112.                     IF right > rightMSArect.left THEN
  1113.                         right := rightMSArect.left;
  1114.                 onScreenRgn := NewRgn;
  1115.                 RectRgn(onScreenRgn, visDrawingRect);
  1116.                 CalcVis(WindowPeek(wp));                        { Radius' TOM INIT. }
  1117.                 SectRgn(onScreenRgn, wp^.visRgn, onScreenRgn);
  1118.                 CopyBits(offBitMapPtr^, wp^.portBits, offBarRect, drawingRect, srcCopy, onScreenRgn);
  1119.  
  1120.       { Consider you're CMD-dragging ... }
  1121.                 IF NOT active THEN
  1122.                     DimRgn(onScreenRgn);
  1123.                 ValidRgn(onScreenRgn);
  1124.                 DisposeRgn(onScreenRgn);
  1125.             END;   { WITH barOSHdl^^ }
  1126. 200:
  1127.             DisposOffScreen(barOSHdl);
  1128.  
  1129.         END;   { WITH theMenuBar^^ }
  1130.  
  1131.         HSetState(Handle(theMenuBar), mbHState);            { Deliberately last !! }
  1132.                                                         { ... we're safe now   }
  1133.         RestoreColors;
  1134.         IF aMac2 THEN
  1135.             SetMCInfo(oldMCTable);
  1136.         ;
  1137.         SetClip(oldClip);
  1138.         DisposeRgn(oldClip);
  1139.         SetPort(oldPort);
  1140.  
  1141.         wHiliteMenu(theMenuBar, 0);             { Appropriate highlighting = none. }
  1142.  
  1143.     END;   { wDrawMenuBar }
  1144.  
  1145.  
  1146.     PROCEDURE wScrollMenuBar (theMenuBar: wMenuBarHandle);
  1147.  
  1148.         CONST
  1149.             toRight = 1;
  1150.             toLeft = -1;
  1151.  
  1152.         VAR
  1153.             mouseLoc: Point;
  1154.             nbrMenus, direction, temp, deltaScroll, i: INTEGER;
  1155.  
  1156.  
  1157.     BEGIN
  1158.  
  1159.         nbrMenus := theMenuBar^^.numMenus;
  1160.  
  1161.         GetMouse(mouseLoc);
  1162.         IF PtInRect(mouseLoc, leftMSArect) THEN
  1163.             direction := toRight
  1164.         ELSE IF PtInRect(mouseLoc, rightMSArect) THEN
  1165.             direction := toLeft
  1166.         ELSE
  1167.             EXIT(wScrollMenuBar);          { Should NOT happen !! }
  1168.  
  1169.         WHILE WaitMouseUp DO
  1170.         BEGIN
  1171.             IF direction = toRight THEN
  1172.             BEGIN
  1173.                 temp := leftMSArect.right + betweenTitles - invertOverlap - mBar^^.wMenus[0].titleRect.left;
  1174.                 IF temp <= 0 THEN
  1175.                     Leave
  1176.                 ELSE
  1177.                     deltaScroll := Min(StringWidth('A'), temp);
  1178.             END
  1179.             ELSE     { direction = toLeft }
  1180.             BEGIN
  1181.                 temp := rightMSArect.left - (mBar^^.wMenus[nbrMenus - 1].titleRect.right - invertOverlap + betweenTitles);
  1182.                 IF temp >= 0 THEN
  1183.                     Leave
  1184.                 ELSE
  1185.                     deltaScroll := Min(StringWidth('A'), -temp);   { Absolute value. }
  1186.             END;
  1187.  
  1188.             deltaScroll := direction * deltaScroll;
  1189.             FOR i := 0 TO (nbrMenus - 1) DO
  1190.                 OffsetRect(theMenuBar^^.wMenus[i].titleRect, deltaScroll, 0);
  1191.             wDrawMSA(theMenuBar);
  1192.             wDrawMenuBar(theMenuBar);
  1193.         END;   { WHILE }
  1194.  
  1195.     END;   { wScrollMenuBar }
  1196.  
  1197.  
  1198.     PROCEDURE wGetMSA (theMenuBar: wMenuBarHandle);
  1199. { NOTE that lines drawn between _OpenPoly & _ClosePoly have zero-width. }
  1200. { Only when _FramePoly actually draws the polygon <see "wDrawMSA">, do  }
  1201. { the pen's attributes such as pen size take effect with the line       }
  1202. { thickness being on the INSIDE.                                        }
  1203.  
  1204.         VAR
  1205.             dx, dy, over, back, up, down: INTEGER;
  1206.             tempPoly: PolyHandle;
  1207.  
  1208.  
  1209.     BEGIN
  1210.  
  1211.         WITH WBMrect DO
  1212.         BEGIN
  1213.             GetPort(oldPort);
  1214.             SetPort(theMenuBar^^.wp);
  1215.  
  1216.             GetWBMrects(theMenuBar^^.wp, WBMrect, leftMSArect, rightMSArect);
  1217.  
  1218.     { ---------- }
  1219.     { Get Menu Scroll Activator(MSA) at left of Window Bar Menu: }
  1220.  
  1221.             dx := 3 * (scrollPolyDXY DIV 2);
  1222.             dy := (bottom - menuFrame - top - scrollPolyDXY) DIV 2;
  1223.             over := scrollPolyDXY;
  1224.             back := -over;
  1225.             up := -scrollPolyDXY;
  1226.             down := scrollPolyDXY DIV 2;
  1227.  
  1228.             IF theMenuBar^^.leftScrollPoly = NIL THEN
  1229.             BEGIN
  1230.       { theMenuBar^^.leftScrollPoly := OpenPoly;  --  I can't believe I did this ?!*!? }
  1231.                 tempPoly := OpenPoly;
  1232.                 theMenuBar^^.leftScrollPoly := tempPoly;
  1233.                 MoveTo(left + dx, bottom - menuFrame - dy);
  1234.                 Line(0, up);                     { Vertical part ...     }
  1235.                 Line(back, down);                { ... horizontal parts: }
  1236.                 Line(over, down);
  1237.                 ClosePoly;
  1238.             END;   { Doesn't exist, so make a new one }
  1239.  
  1240.     { ---------- }
  1241.     { Get MSA at right of Window Bar Menu: }
  1242.  
  1243.             IF theMenuBar^^.rightScrollPoly = NIL THEN
  1244.             BEGIN
  1245.                 tempPoly := OpenPoly;
  1246.                 theMenuBar^^.rightScrollPoly := tempPoly;
  1247.                 MoveTo(right - dx, bottom - menuFrame - dy);
  1248.                 Line(0, up);                     { Vertical part ...     }
  1249.                 Line(over, down);                { ... horizontal parts: }
  1250.                 Line(back, down);
  1251.                 ClosePoly;
  1252.             END;   { IF }
  1253.  
  1254.             SetPort(oldPort);
  1255.         END;   { WITH WBMrect }
  1256.  
  1257.     END;   { wGetMSA }
  1258.  
  1259.  
  1260.     PROCEDURE wDrawMSA (theMenuBar: wMenuBarHandle);
  1261. { ... AND the bottom line bordering the Window Bar Menu.   }
  1262.  
  1263.         LABEL
  1264.             100;
  1265.  
  1266.         VAR
  1267.             dx, dy: INTEGER;
  1268.             aux: BOOLEAN;
  1269.             frameColor: RGBColor;
  1270.  
  1271.  
  1272.     BEGIN
  1273.  
  1274.         WITH WBMrect DO
  1275.         BEGIN
  1276.             GetPort(oldPort);
  1277.             SetPort(theMenuBar^^.wp);
  1278.             GetPenState(pnState);
  1279.  
  1280.     { ---------- }
  1281.     { Get the Window Bar Menu rect & draw a line beneath it: }
  1282.  
  1283.             wGetMSA(theMenuBar);                         { Calls GetWBMrects. }
  1284.             gWBMrect := WBMrect;
  1285.             LocalGlobal(gWBMrect);
  1286.             IF NOT SectRect(gWBMrect, gScreen, visRect) THEN
  1287.                 GOTO 100;
  1288.             GlobalLocal(visRect);
  1289.             onScreenRgn := NewRgn;
  1290.             RectRgn(onScreenRgn, visRect);
  1291.             SectRgn(onScreenRgn, theMenuBar^^.wp^.visRgn, onScreenRgn);
  1292.             oldClip := NewRgn;
  1293.             GetClip(oldClip);
  1294.             SetClip(onScreenRgn);
  1295.             ;
  1296.             aux := GetWindowPartColor(theMenuBar^^.wp, wFrameColor, frameColor);
  1297.             IF (colorDepth > 1) & aux THEN
  1298.             BEGIN
  1299.                 GetForeColor(oldForeColor);
  1300.                 RGBForeColor(frameColor);
  1301.             END;   { Draw in color }
  1302.             ;
  1303.             PenNormal;
  1304.             PenSize(menuFrame, menuFrame);
  1305.             MoveTo(left, bottom - menuFrame);
  1306.             Line(right - left, 0);
  1307.  
  1308.     { ---------- }
  1309.     { Draw Menu Scroll Activator(MSA) at left of Window Bar Menu: }
  1310.  
  1311.             IF theMenuBar^^.wMenus[0].titleRect.left < leftMSArect.right + betweenTitles - invertOverlap THEN
  1312.                 FillPoly(theMenuBar^^.leftScrollPoly, black)
  1313.             ELSE
  1314.             BEGIN
  1315.                 FillPoly(theMenuBar^^.leftScrollPoly, white);
  1316.                 FramePoly(theMenuBar^^.leftScrollPoly);
  1317.             END;
  1318.  
  1319.     { ---------- }
  1320.     { Draw vertical line separating MSA from Menu titles: }
  1321.  
  1322.             MoveTo(left + 2 * scrollPolyDXY, bottom - menuFrame);
  1323.             Line(0, -(bottom - top - menuFrame));
  1324.  
  1325.     { ---------- }
  1326.     { Draw MSA at right of Window Bar Menu: }
  1327.  
  1328.             IF theMenuBar^^.wMenus[theMenuBar^^.numMenus - 1].titleRect.right - invertOverlap + betweenTitles > rightMSArect.left THEN
  1329.                 FillPoly(theMenuBar^^.rightScrollPoly, black)
  1330.             ELSE
  1331.             BEGIN
  1332.                 FillPoly(theMenuBar^^.rightScrollPoly, white);
  1333.                 FramePoly(theMenuBar^^.rightScrollPoly);
  1334.             END;
  1335.             ;
  1336.             MoveTo(right - 2 * scrollPolyDXY - menuFrame, bottom - menuFrame);   { + vertical }
  1337.             Line(0, -(bottom - top - menuFrame));                                {   line.    }
  1338.  
  1339.             IF ORD(WindowPeek(theMenuBar^^.wp)^.hilited) = 0 THEN
  1340.                 DimRgn(onScreenRgn);
  1341.  
  1342.             ValidRgn(onScreenRgn);
  1343.             DisposeRgn(onScreenRgn);
  1344.             SetClip(oldClip);
  1345.             DisposeRgn(oldClip);
  1346.  
  1347.             IF (colorDepth > 1) & aux THEN
  1348.                 RGBForeColor(oldForeColor);
  1349. 100:
  1350.             SetPenState(pnState);
  1351.             SetPort(oldPort);
  1352.         END;   { WITH }
  1353.  
  1354.     END;   { wDrawMSA }
  1355.  
  1356.  
  1357.     PROCEDURE wClearMenuBar (theMenuBar: wMenuBarHandle);
  1358. { Called internally by wDeleteWMB to kiss some Handles goodbye. }
  1359.  
  1360.  
  1361.     BEGIN
  1362.  
  1363.         mbHState := HGetState(Handle(theMenuBar));
  1364.         MoveHHi(Handle(theMenuBar));
  1365.         HLock(Handle(theMenuBar));
  1366.  
  1367.         WITH theMenuBar^^ DO
  1368.         BEGIN
  1369.             wHiliteMenu(theMenuBar, 0);
  1370.  
  1371.             IF leftScrollPoly <> NIL THEN                   { So sue me ... I'm paranoid !! }
  1372.             BEGIN
  1373.                 KillPoly(leftScrollPoly);
  1374.                 leftScrollPoly := NIL;                         { Mark as gone ... }
  1375.             END;
  1376.             ;
  1377.             IF rightScrollPoly <> NIL THEN
  1378.             BEGIN
  1379.                 KillPoly(rightScrollPoly);
  1380.                 rightScrollPoly := NIL;
  1381.             END;
  1382.  
  1383.             IF barOSHdl <> NIL THEN
  1384.                 DisposOffScreen(barOSHdl);                         { Sets barOSHdl := NIL }
  1385.         END;   { WITH }
  1386.  
  1387.         HSetState(Handle(theMenuBar), mbHState);
  1388.  
  1389.     END;   { wClearMenuBar }
  1390.  
  1391.  
  1392.     FUNCTION wMenuSelect (theMenuBar: wMenuBarHandle; startPt: Point): LONGINT;
  1393. { Pull down the Menus and let the user select an Item: }
  1394. { NOTE -- "startPt" is in Global coordinates, but      }
  1395. {         ONLY to be compatible with _MenuSelect.      }
  1396.  
  1397.         LABEL
  1398.             100, 200;
  1399.  
  1400.         CONST
  1401.             TopMenuItemLoc = $A0A;
  1402.             AtMenuBottomLoc = $A0C;
  1403.             MenuFlashAddr = $A24;
  1404.             HiliteMode = $938;
  1405.  
  1406.         VAR
  1407.             oldPort: GrafPtr;                       { Many Locals because of recursion ... }
  1408.             oldClip: RgnHandle;
  1409.             oldForeColor, oldBackColor: RGBColor;
  1410.             screenBounds, betweenMSAs, visAllTitles, visThisTitle, visString: Rect;
  1411.             menuRect, menuFrameRect, lsMenuRect, lsWBMrect, lsTitleRect: Rect;
  1412.             lStartPt, hierPt, nilPt: Point;
  1413.             itemsHeight, i, j, blink: INTEGER;
  1414.             saveScrollInfo: LONGINT;
  1415.             menuFlashP: wordPtr;
  1416.             strayed: BOOLEAN;
  1417.             cmdChar, itemMark: char;
  1418.             hierMenuHdl: MenuHandle;
  1419.             origMCTable, parentMCTable, hierMCTable: MCTableHandle;
  1420.             hierSelect: LONGINT;
  1421.             onCScreen: CGrafPort;
  1422.             onCScreenPtr: CGrafPtr;
  1423.             onBWScreen: GrafPort;
  1424.             onBWScreenPtr: GrafPtr;
  1425.             MenuDownOSHdl: OffScreenRecHdl;
  1426.     { Murphy's Memory Manager ... }
  1427.             tempRgn1, tempRgn2, tempRgn3: RgnHandle;
  1428.  
  1429.  
  1430.         FUNCTION ItDoesFit (theMenu: MenuHandle; maxMenuHeight: INTEGER; VAR cumMenuHeight: INTEGER): BOOLEAN;
  1431.   { Get maximum cum height that can fit within the specified max height. }
  1432.  
  1433.             VAR
  1434.                 prevMenuHeight, index, sizeItemIcon: INTEGER;
  1435.  
  1436.  
  1437.         BEGIN
  1438.  
  1439.             ItDoesFit := true;                    { Be upbeat !! }
  1440.             IF theMenu^^.menuHeight <= maxMenuHeight THEN
  1441.             BEGIN
  1442.                 cumMenuHeight := theMenu^^.menuHeight;
  1443.                 EXIT(ItDoesFit);
  1444.             END;
  1445.  
  1446.             cumMenuHeight := 0;                   { For starters ... }
  1447.  
  1448.             FOR index := 1 TO CountMItems(theMenu) DO
  1449.             BEGIN
  1450.                 prevMenuHeight := cumMenuHeight;
  1451.                 sizeItemIcon := GetItemIconSize(theMenu, index);
  1452.                 cumMenuHeight := cumMenuHeight + aboveBelowItem + Max(sizeFont, sizeItemIcon) + aboveBelowItem;
  1453.                 IF cumMenuHeight > maxMenuHeight THEN
  1454.                     Leave;   { FOR loop }
  1455.             END;   { FOR }
  1456.  
  1457.             IF index - 1 < 3 THEN
  1458.                 ItDoesFit := false
  1459.             ELSE IF sizeItemIcon = 0 THEN        { ... of first item NOT shown. }
  1460.                 cumMenuHeight := prevMenuHeight
  1461.             ELSE
  1462.       { Prevents drawing of the top pixels of any icon in first item NOT shown: }
  1463.                 cumMenuHeight := prevMenuHeight - aboveBelowItem;
  1464.  
  1465.         END;   { ItDoesFit }
  1466.  
  1467.  
  1468.         FUNCTION GetParentMenuInfo (theMenuBar: wMenuBarHandle; hierMenuNbr: INTEGER): LONGINT;
  1469.   { Returns parent menu # in Hi word and parent item # in the low word: }
  1470.   {                   NEVER say it can NEVER fail !!!                   }
  1471.  
  1472.             VAR
  1473.                 hierID, parentMenuNum, j: INTEGER;
  1474.                 parentMenuHdl: MenuHandle;
  1475.                 cmdChar, parentMark: char;
  1476.                 temp: LONGINT;
  1477.  
  1478.  
  1479.         BEGIN
  1480.  
  1481.             WITH theMenuBar^^ DO
  1482.             BEGIN
  1483.                 parentMenuNum := 0;
  1484.                 WHILE (parentMenuNum < numMenus) & (wMenus[hierMenuNbr].parentID <> wMenus[parentMenuNum].mh^^.menuID) DO
  1485.                     parentMenuNum := parentMenuNum + 1;
  1486.  
  1487.                 IF parentMenuNum = numMenus THEN     { It better NOT be !!! }
  1488.                     ;
  1489.                 hierID := wMenus[hierMenuNbr].mh^^.menuID;
  1490.                 parentMenuHdl := wMenus[parentMenuNum].mh;
  1491.             END;   { WITH }
  1492.  
  1493.             FOR j := 1 TO CountMItems(parentMenuHdl) DO
  1494.             BEGIN
  1495.                 GetItemCmd(parentMenuHdl, j, cmdChar);
  1496.                 IF cmdChar = char(hMenuCmd) THEN
  1497.                 BEGIN
  1498.                     GetItemMark(parentMenuHdl, j, parentMark);
  1499.                     IF ord(parentMark) = hierID THEN
  1500.                         Leave;   { FOR loop }
  1501.                 END;
  1502.             END;   { FOR }
  1503.  
  1504.             temp := parentMenuNum;
  1505.             temp := BitShift(temp, 16) + j;
  1506.             GetParentMenuInfo := temp;
  1507.  
  1508.         END;   { GetParentMenuInfo }
  1509.  
  1510.  
  1511.         PROCEDURE RedrawParentItem (theMenuBar: wMenuBarHandle; hierMenuNbr: INTEGER);
  1512.   { Apple's MenuDefProc does NOT call _InverRect for a color Mac, }
  1513.   { but rather _EraseRect followed by a redraw of the Menu item   }
  1514.   { with reversed background and hilite colors.  As you can see   }
  1515.   { below, however, I am prone to cheating:                       }
  1516.  
  1517.  
  1518.     { CONST                    }
  1519.     {  TopMenuItemLoc = $A0A;  }
  1520.     {  AtMenuBottomLoc = $A0C; }
  1521.  
  1522.             VAR
  1523.                 saveScrollInfo: LONGINT;            { MUST be local !!! }
  1524.                 parentMenuInfo: LONGINT;
  1525.                 parentMenuNum, redrawitem: INTEGER;
  1526.                 redrawPt: Point;
  1527.                 parentMenuHdl: MenuHandle;
  1528.                 parentMenuRect: Rect;
  1529.  
  1530.  
  1531.         BEGIN
  1532.  
  1533.             IF NOT aMac2 THEN
  1534.                 EXIT(RedrawParentItem);
  1535.  
  1536.             parentMenuInfo := GetParentMenuInfo(theMenuBar, hierMenuNbr);
  1537.             parentMenuNum := HiWord(parentMenuInfo);
  1538.             redrawItem := LoWord(parentMenuInfo);
  1539.  
  1540.             WITH theMenuBar^^.wMenus[parentMenuNum] DO
  1541.             BEGIN
  1542.                 parentMenuHdl := mh;
  1543.                 parentMenuRect := menuParentRgn^^.rgnBBox;
  1544.             END;
  1545.             ClipRect(parentMenuRect);             { For call to "mChooseMsg" below. }
  1546.             WITH lScreen DO                      { LocalToGlobal }
  1547.                 OffsetRect(parentMenuRect, -left, -top);
  1548.  
  1549.             SetPt(redrawPt, 0, 0);
  1550.             saveScrollInfo := longPtr(TopMenuItemLoc)^;
  1551.             wordPtr(TopMenuItemLoc)^ := parentMenuRect.top;
  1552.             wordPtr(AtMenuBottomLoc)^ := parentMenuRect.bottom;
  1553.             MenuDefGlue(mChooseMsg, parentMenuHdl, parentMenuRect, redrawPt, redrawItem);
  1554.             longPtr(TopMenuItemLoc)^ := saveScrollInfo;
  1555.  
  1556.         END;   { RedrawParentItem }
  1557.  
  1558.  
  1559.     BEGIN   { wMenuSelect }
  1560.  
  1561.   { Note that starting here, we sure could use WITH theMenuBar^^ & WITH wMenus[i]  }
  1562.   { statements for shorthand.  However, we'd then need to call HLock.  This would  }
  1563.   { be okay except when we later implement Hierarchical menus via a recursive      }
  1564.   { to ourself (wMenuSelect).  This unnecessarily keeps a locked Handle around for }
  1565.   { a long time.  [ See "The Secret Life of the Memory Manager" by Richard Clark   }
  1566.   { in "develop", Volume 1, Issue 2, April 1990 ]  In addition, for Hierarchical   }
  1567.   { menus, we call wInsertMenu and wDeleteMenu which in turn call the IncreaseSize }
  1568.   { and DecreaseSize PROCs.  These latter PROCs move "theMenuBar" because we need  }
  1569.   { to temporarily unlock this handle ... therefore ...                            }
  1570.  
  1571.         GetPort(oldPort);
  1572.         SetPort(theMenuBar^^.wp);
  1573.         oldClip := NewRgn;
  1574.         GetClip(oldClip);
  1575.         ;
  1576.         IF aMac2 THEN
  1577.         BEGIN
  1578.             GetBackColor(oldBackColor);           { "GetColors" is local due to recursion. }
  1579.             GetForeColor(oldForeColor);
  1580.             origMCTable := GetMCInfo;
  1581.             SetMCInfo(theMenuBar^^.wMCTable);
  1582.         END;   { IF aMac2 }
  1583.         ;
  1584.         menuFlashP := wordPtr(MenuFlashAddr);
  1585.  
  1586.         WHILE WaitMouseUp DO
  1587.         BEGIN
  1588.  
  1589.             whichItem := 0;                       { May NOT be in a titleRect. }
  1590.  
  1591.             i := theMenuBar^^.numMenus - 1;       { Find the Menu title that user is selecting. }
  1592.             GlobalToLocal(startPt);               { Local window coordinates. }
  1593.             WHILE (i >= 0) & NOT PtInRect(startPt, theMenuBar^^.wMenus[i].titleRect) DO
  1594.                 i := i - 1;
  1595.  
  1596.             IF i >= 0 THEN                       { Have Menu drop ... }
  1597.             BEGIN
  1598.  
  1599.                 lsTitleRect := theMenuBar^^.wMenus[i].titleRect;
  1600.                 ;
  1601.                 IF theMenuBar^^.wMenus[i].menuType = regMenu THEN
  1602.                 BEGIN
  1603.  
  1604.         { Otherwise strayed = TRUE momentarily as you hit the line bordering      }
  1605.         { titleRect & menuRect in the process of pulling down a MENU (see below): }
  1606.                     lsTitleRect.bottom := lsTitleRect.bottom + menuFrame;
  1607.  
  1608.         {            ... AND if the Window Menu Bar is scrolled ...              }
  1609.         { don't forget about the invertOverlap arithmetic which would enable the }
  1610.         { Mouse to be over the expanded titleRect WITHOUT the first/last title   }
  1611.         { character being visible.  The equations below avoid this happenstance. }
  1612.         { In addition, "menuFrame" is used to account for a character width > an }
  1613.         { image width as well as a character origin > 0.                         }
  1614.  
  1615.                     screenBounds := gScreen;
  1616.                     GlobalLocal(screenBounds);
  1617.                     betweenMSAs := WBMrect;
  1618.                     InsetRect(betweenMSAs, leftMSArect.right, 0);   { ... or rightMSArect.left }
  1619.                     IF NOT SectRect(screenBounds, betweenMSAs, visAllTitles) THEN
  1620.                         GOTO 100;                      { Will NOT happen !! }
  1621.  
  1622.                     IF NOT SectRect(visAllTitles, lsTitleRect, visThisTitle) THEN
  1623.                         GOTO 100;                      { Ditto !! }
  1624.  
  1625.                     visString := visThisTitle;
  1626.                     WITH visString DO
  1627.                     BEGIN
  1628.                         IF (leftMSArect.right > right - invertOverlap - 2 * menuFrame) | (screenBounds.left > right - invertOverlap - 2 * menuFrame) THEN
  1629.                             right := right - invertOverlap - 2 * menuFrame;
  1630.                         ;
  1631.                         IF (rightMSArect.left < left + invertOverlap + 2 * menuFrame) | (screenBounds.right < left + invertOverlap + 2 * menuFrame) THEN
  1632.                             left := left + invertOverlap + 2 * menuFrame;
  1633.                     END;   { WITH visString }
  1634.                     IF EmptyRect(visString) THEN
  1635.                         GOTO 100;
  1636.  
  1637.                 END;   { a regular Menu }
  1638.  
  1639.                 LocalGlobal(lsTitleRect);
  1640.  
  1641.                 lsWBMrect := WBMrect;               { Needed for vertical scrolling ... }
  1642.                 InsetRect(lsWBMrect, leftMSArect.right, 0);  { ... or rightMSArect.left }
  1643.                 LocalGlobal(lsWBMrect);
  1644.  
  1645.                 LocalToGlobal(startPt);
  1646.  
  1647.                 CalcMenuSize(theMenuBar^^.wMenus[i].mh);
  1648.  
  1649.                 WITH theMenuBar^^.wMenus[i], titleRect DO
  1650.                     IF menuType = regMenu THEN
  1651.                         SetRect(menuFrameRect, left, bottom, left + menuFrame + mh^^.menuWidth + frameShad, bottom + menuFrame + mh^^.menuHeight + frameShad)
  1652.                     ELSE
  1653.                         SetRect(menuFrameRect, right - 4 * menuFrame, top, right - 4 * menuFrame + menuFrame + mh^^.menuWidth + frameShad, top + menuFrame + mh^^.menuHeight + frameShad);
  1654.  
  1655.       { If Menu overlaps the screen's edges, trim and/or shift it: }
  1656.                 LocalGlobal(menuFrameRect);
  1657.                 WITH gScreen DO
  1658.                 BEGIN
  1659.                     IF menuFrameRect.bottom > bottom - 2 * menuFrame THEN
  1660.                         menuFrameRect.bottom := bottom - 2 * menuFrame;
  1661.                     ;
  1662.                     IF menuFrameRect.right > right - 2 * menuFrame THEN  { Shift left. }
  1663.                         IF theMenuBar^^.wMenus[i].menuType = regMenu THEN
  1664.                             OffsetRect(menuFrameRect, right - 2 * menuFrame - menuFrameRect.right, 0)
  1665.                         ELSE
  1666.                             OffsetRect(menuFrameRect, -(theMenuBar^^.wMenus[i].titleRect.right - theMenuBar^^.wMenus[i].titleRect.left - 8 * menuFrame + (menuFrameRect.right - menuFrameRect.left)), 0);
  1667.                     ;
  1668.                     IF menuFrameRect.left < left + 2 * menuFrame THEN    { Shift right. }
  1669.                         OffsetRect(menuFrameRect, left + 2 * menuFrame - menuFrameRect.left, 0);
  1670.                 END;   { WITH gScreen }
  1671.                 GlobalLocal(menuFrameRect);        { Back to local window coordinates. }
  1672.  
  1673.                 WITH menuFrameRect DO
  1674.                     IF ItDoesFit(theMenuBar^^.wMenus[i].mh, bottom - top - menuFrame - frameShad, itemsHeight) THEN
  1675.                         bottom := top + menuFrame + itemsHeight + frameShad
  1676.                     ELSE IF theMenuBar^^.wMenus[i].menuType = regMenu THEN
  1677.                     BEGIN                      { Damn SysBeep drove me nuts/nuttier !!! }
  1678.                         wHiliteMenu(theMenuBar, theMenuBar^^.wMenus[i].mh^^.menuID);
  1679.                         Delay(flashDelay * 2, finalTicks);
  1680.                         wHiliteMenu(theMenuBar, 0);
  1681.                         Delay(flashDelay * 2, finalTicks);
  1682.                         GOTO 100;
  1683.                     END
  1684.                     ELSE
  1685.                     BEGIN
  1686.                         SetPort(oldPort);         { From Open(C)Port on the previous go-around. }
  1687.                         WITH lScreen DO
  1688.                             OffsetRect(lsTitleRect, left, top);    { GlobalToLocal }
  1689.                         Delay(flashDelay * 2, finalTicks);
  1690.                         IF aMac2 THEN
  1691.                             RedrawParentItem(theMenuBar, i)        { i = Hierarchical Menu # }
  1692.                         ELSE
  1693.                         BEGIN
  1694.                             ClipRect(lsTitleRect);
  1695.                             InvertRect(lsTitleRect);
  1696.                         END;
  1697.                         Delay(flashDelay * 2, finalTicks);
  1698.                         SetPort(theMenuBar^^.wp);                { So we can reset its clipRgn on exit. }
  1699.                         Leave;
  1700.                     END;   { does NOT fit & WITH menuFrameRect }
  1701.  
  1702.       { MenuDefProc's "mChooseMsg" handles hiliting for a Hierarchical menu item: }
  1703.                 IF theMenuBar^^.wMenus[i].menuType = regMenu THEN
  1704.                     wHiliteMenu(theMenuBar, theMenuBar^^.wMenus[i].mh^^.menuID);
  1705.  
  1706.                 MenuDownOSHdl := CreateOffScreen(menuFrameRect);
  1707.                 IF (QuickStrip(Ptr(MenuDownOSHdl)) = NIL) | (MenuDownOSHdl^^.CreateOffScreenError <> noErr) THEN
  1708.                 BEGIN
  1709.                     DisposOffScreen(MenuDownOSHdl);
  1710.                     GOTO 200;
  1711.                 END;   { Whoops !! }
  1712.  
  1713.                 ClipRect(menuFrameRect);                         { Draw off-screen ... }
  1714.                 EraseRect(menuFrameRect);                        { Eliminate all stray matter. }
  1715.  
  1716.       { An alternate "ToOnScreen" so our Menu can overlap the window's }
  1717.       { boundaries rather than be confined to just its portRect:       }
  1718.                 IF aMac2 THEN
  1719.                 BEGIN
  1720.                     SetGDevice(MenuDownOSHdl^^.oldDevice);
  1721.                     onCScreenPtr := @onCScreen;
  1722.                     OpenCPort(onCScreenPtr);
  1723.                     RectRgn(onCScreenPtr^.visRgn, gScreen);       { Multiple screens ... }
  1724.                     onCScreenPtr^.portRect := gScreen;
  1725.                 END   { IF aMac2 }
  1726.                 ELSE
  1727.                 BEGIN
  1728.                     onBWScreenPtr := @onBWScreen;
  1729.                     OpenPort(onBWScreenPtr);
  1730.                     RectRgn(onBWScreenPtr^.visRgn, gScreen);
  1731.                     onBWScreenPtr^.portRect := gScreen;
  1732.                 END;   { ELSE = "Yucky" black-and-white }
  1733.  
  1734.                 ClipRect(menuFrameRect);
  1735.       { Save current screen image: }
  1736.                 BackColor(whiteColor);
  1737.                 ForeColor(blackColor);
  1738.                 CopyBits(thePort^.portBits, MenuDownOSHdl^^.offBitMapPtr^, menuFrameRect, menuFrameRect, srcCopy, NIL);
  1739.  
  1740.                 TextFont(systemFont);
  1741.                 myTextSize(sizeFont);
  1742.                 TextFace([]);
  1743.                 TextMode(srcOr);
  1744.  
  1745.       { NOW, the magic ~~ Mike Shuster, MacTutor <Dec, 85> }
  1746.  
  1747.                 menuRect := menuFrameRect;
  1748.                 WITH menuRect DO
  1749.                 BEGIN                                            { Draw frame, then shadow. }
  1750.                     GetPenState(pnState);
  1751.                     PenNormal;
  1752.  
  1753.                     right := right - menuShadow;
  1754.                     bottom := bottom - menuShadow;
  1755.                     wSetColorMenu(theMenuBar^^.wMenus[i].mh^^.menuID, mceMenuTitle);
  1756.                     EraseRect(menuRect);                            { Inside shadow. }
  1757.                     PenSize(menuFrame, menuFrame);
  1758.                     FrameRect(menuRect);
  1759.                     InsetRect(menuRect, menuFrame, menuFrame);      { Inside frame AND shadow. }
  1760.                     ;
  1761.                     MoveTo(left + menuShadow, bottom + menuFrame);
  1762.                     PenSize(menuShadow, menuShadow);
  1763.                     Line((right - left + menuFrame), 0);
  1764.                     MoveTo(right + menuFrame, bottom + frameShad);
  1765.                     Line(0, -(bottom - top + menuFrame));
  1766.  
  1767.                     SetPenState(pnState);
  1768.                 END;   { WITH menuRect }
  1769.  
  1770.                 lsMenuRect := menuRect;                           { Save for later ... }
  1771.  
  1772.                 WITH lScreen DO
  1773.                 BEGIN
  1774.                     OffsetRect(menuRect, -left, -top);              { LocalToGlobal }
  1775.                     OffsetRect(lsTitleRect, left, top);             { GlobalToLocal ... }
  1776.                     OffsetRect(lsWBMrect, left, top);
  1777.                 END;   { WITH lScreen }
  1778.  
  1779.                 IF theMenuBar^^.wMenus[i].menuType = regMenu THEN   { ... or parentID = mainMenu. }
  1780.                 BEGIN
  1781.                     tempRgn1 := NewRgn;
  1782.                     RectRgn(tempRgn1, lsWBMrect);
  1783.                     theMenuBar^^.wMenus[i].cumParentRgn := tempRgn1;
  1784.                     tempRgn2 := NewRgn;
  1785.                     RectRgn(tempRgn2, lsMenuRect);
  1786.                     theMenuBar^^.wMenus[i].menuParentRgn := tempRgn2;
  1787.                 END
  1788.                 ELSE
  1789.                 BEGIN
  1790.                     j := HiWord(GetParentMenuInfo(theMenuBar, i));  { i = Hierarchical Menu # }
  1791.                     tempRgn1 := NewRgn;
  1792.                     tempRgn2 := theMenuBar^^.wMenus[j].cumParentRgn;
  1793.                     tempRgn3 := theMenuBar^^.wMenus[j].menuParentRgn;
  1794.                     UnionRgn(tempRgn2, tempRgn3, tempRgn1);
  1795.                     theMenuBar^^.wMenus[i].cumParentRgn := tempRgn1;
  1796.                     tempRgn2 := NewRgn;
  1797.                     RectRgn(tempRgn2, lsMenuRect);
  1798.                     theMenuBar^^.wMenus[i].menuParentRgn := tempRgn2;
  1799.                 END;
  1800.  
  1801.       { Start fresh with each scrollable Menu: }
  1802.                 saveScrollInfo := longPtr(TopMenuItemLoc)^;
  1803.                 wordPtr(TopMenuItemLoc)^ := menuRect.top;
  1804.                 wordPtr(AtMenuBottomLoc)^ := menuRect.bottom;
  1805.  
  1806.       { I encountered a few "cosmetic" problems with Apple's MenuDefProc.           }
  1807.       {   1) the disabled dotted line will overwrite the right border of the frame. }
  1808.       {   2) if there is an icon immediately below the last item that shows in a    }
  1809.       {      scrolling menu, the bottom border of the frame is overwritten by a     }
  1810.       {      portion of said icon.                                                  }
  1811.       { The call to ClipRect solves both:                                           }
  1812.                 ClipRect(lsMenuRect);
  1813.       { whichItem := 0;     --     at beginning of WHILE WaitMouseUp DO }
  1814.                 MenuDefGlue(mDrawMsg, theMenuBar^^.wMenus[i].mh, menuRect, startPt, whichItem);
  1815.  
  1816.                 strayed := false;                      { = Mouse on Menu Item OR on Menu title }
  1817.                                                {   OR NOT on another Menu.             }
  1818.                 WHILE WaitMouseup & NOT strayed DO   { While still selecting in this Menu ... }
  1819.                 BEGIN
  1820.                     GetMouse(startPt);
  1821.                     lStartPt := startPt;
  1822.                     SubPt(lScreen.topLeft, startPt);     { LocalToGlobal }
  1823.                     MenuDefGlue(mChooseMsg, theMenuBar^^.wMenus[i].mh, menuRect, startPt, whichItem);
  1824.  
  1825.                     IF whichItem <> 0 THEN              { Item is enabled. }
  1826.                     BEGIN
  1827.                         GetItemCmd(theMenuBar^^.wMenus[i].mh, whichItem, cmdChar);
  1828.  
  1829.                         IF cmdChar = char(hMenuCmd) THEN  { a Hierarchical Menu ... }
  1830.                         BEGIN
  1831.                             IF aMac2 THEN
  1832.                                 parentMCTable := theMenuBar^^.wMCTable;
  1833.                             hierPt := startPt;
  1834.                             GetItemMark(theMenuBar^^.wMenus[i].mh, whichItem, itemMark);
  1835.                             hierMenuHdl := GetMenu(ord(itemMark));
  1836.                             wInsertMenu(theMenuBar, hierMenuHdl, hierMenu);
  1837.                             DetachResource(Handle(hierMenuHdl));
  1838.                             IF aMac2 THEN
  1839.                             BEGIN
  1840.                                 hierMCTable := GetMCInfo;
  1841.                                 SetMCInfo(parentMCTable);
  1842.                                 theMenuBar^^.wMCTable := hierMCTable;
  1843.                             END;   { IF aMac2 }
  1844.                             hierSelect := wMenuSelect(theMenuBar, hierPt);
  1845.                             wDeleteMenu(theMenuBar, ord(itemMark));
  1846.                             ;
  1847.                             whichMenu := HiWord(hierSelect);
  1848.                             whichItem := LoWord(hierSelect);
  1849.  
  1850.                             IF whichItem <> 0 THEN     { So a parent Menu Item does NOT blink: }
  1851.                             BEGIN
  1852.                                 strayed := true;
  1853.                                 Leave;
  1854.                             END;
  1855.                         END
  1856.  
  1857.                         ELSE  { a regular Menu }
  1858.                             whichMenu := theMenuBar^^.wMenus[i].mh^^.menuID;
  1859.  
  1860.                     END;   { enabled Item }
  1861.  
  1862.                     strayed := NOT PtInRgn(lStartPt, theMenuBar^^.wMenus[i].menuParentRgn) & NOT PtInRect(lStartPt, lsTitleRect) & PtInRgn(lStartPt, theMenuBar^^.wMenus[i].cumParentRgn);
  1863.                 END;   { WHILE WaitMouseup & NOT strayed }
  1864.  
  1865.                 IF (whichItem <> 0) & NOT strayed THEN
  1866.                     FOR blink := 1 TO menuFlashP^ DO
  1867.                     BEGIN
  1868.                         SetPt(nilPt, 0, 0);
  1869.                         MenuDefGlue(mChooseMsg, theMenuBar^^.wMenus[i].mh, menuRect, nilPt, whichItem);
  1870.                         Delay(flashDelay DIV 4, finalTicks);
  1871.                         MenuDefGlue(mChooseMsg, theMenuBar^^.wMenus[i].mh, menuRect, startPt, whichItem);
  1872.                         Delay(flashDelay DIV 4, finalTicks);
  1873.                     END;   { blinking the selected item }
  1874.  
  1875.                 ClipRect(menuFrameRect);
  1876.                 BackColor(whiteColor);
  1877.                 ForeColor(blackColor);
  1878.       { Blit back original screen image.  For a Hierarchical menu }
  1879.       { item, the off-screen bitMap/pixMap will include a part of }
  1880.       { the inverted parent item.  Therefore, we must first blit  }
  1881.       { back and THEN re-invert !!!                               }
  1882.                 CopyBits(MenuDownOSHdl^^.offBitMapPtr^, thePort^.portBits, menuFrameRect, menuFrameRect, srcCopy, NIL);
  1883.  
  1884.       { Un-hilite the title: }
  1885.                 IF theMenuBar^^.wMenus[i].menuType = regMenu THEN
  1886.                     wHiliteMenu(theMenuBar, 0)
  1887.                 ELSE IF aMac2 THEN
  1888.                     RedrawParentItem(theMenuBar, i)   { i = Hierarchical Menu # }
  1889.                 ELSE
  1890.                 BEGIN
  1891.                     ClipRect(lsTitleRect);
  1892.                     InvertRect(lsTitleRect);
  1893.                 END;
  1894.  
  1895.                 IF aMac2 THEN
  1896.                     CloseCPort(onCScreenPtr)
  1897.                 ELSE
  1898.                     ClosePort(onBWScreenPtr);
  1899.  
  1900.                 SetPort(theMenuBar^^.wp);
  1901.       { Original menuFrameRect in window coordinates: }
  1902.                 ValidRect(MenuDownOSHdl^^.drawingRect);
  1903.                 DisposOffScreen(MenuDownOSHdl);
  1904.  
  1905.                 DisposeRgn(theMenuBar^^.wMenus[i].menuParentRgn);
  1906.                 DisposeRgn(theMenuBar^^.wMenus[i].cumParentRgn);
  1907.                 longPtr(TopMenuItemLoc)^ := saveScrollInfo;
  1908.                 IF theMenuBar^^.wMenus[i].menuType = hierMenu THEN
  1909.                     Leave;
  1910.  
  1911.             END   { IF i >= 0 }
  1912.  
  1913.             ELSE   { User is not over a Menu. }
  1914.                 ;
  1915. 100:
  1916.             GetMouse(startPt);
  1917.             LocalToGlobal(startPt);
  1918.  
  1919.         END;   { WHILE WaitMouseUp }
  1920.  
  1921.         IF whichItem = 0 THEN
  1922.             wMenuSelect := 0
  1923.         ELSE
  1924.             wMenuSelect := BitShift(whichMenu, 16) + whichItem;
  1925. 200:
  1926.         IF aMac2 THEN
  1927.         BEGIN
  1928.             RGBBackColor(oldBackColor);     { "SetColors" is local due to recursion. }
  1929.             RGBForeColor(oldForeColor);
  1930.             SetMCInfo(origMCTable);
  1931.         END;   { aMac2 }
  1932.         ;
  1933.         SetClip(oldClip);
  1934.         DisposeRgn(oldClip);
  1935.         SetPort(oldPort);
  1936.  
  1937.     END;   { wMenuSelect }
  1938.  
  1939.  
  1940.     FUNCTION wMenuKey (theMenuBar: wMenuBarHandle; ch: char): LONGINT;
  1941.  
  1942.         VAR
  1943.             i, j, whichMenu, whichItem: INTEGER;
  1944.             found, enabled: BOOLEAN;
  1945.             cmdChar: char;
  1946.  
  1947.         FUNCTION equalChars (c1, c2: char): BOOLEAN;
  1948.   { Filter out difference between UPPER and lower case: }
  1949.  
  1950.         BEGIN
  1951.             IF c1 IN ['a'..'z'] THEN
  1952.                 c1 := char(ord(c1) + ord('A') - ord('a'));
  1953.             IF c2 IN ['a'..'z'] THEN
  1954.                 c2 := char(ord(c2) + ord('A') - ord('a'));
  1955.             equalChars := (c1 = c2);
  1956.         END;   { equalChars }
  1957.  
  1958.  
  1959.     BEGIN   { wMenuKey }
  1960.  
  1961.         mbHState := HGetState(Handle(theMenuBar));
  1962.         MoveHHi(Handle(theMenuBar));
  1963.         HLock(Handle(theMenuBar));
  1964.  
  1965.         found := false;
  1966.         i := 0;
  1967.  
  1968.         WITH theMenuBar^^ DO
  1969.         BEGIN
  1970.  
  1971.             WHILE (NOT found) & (i < numMenus) DO
  1972.             BEGIN
  1973.  
  1974.                 WITH wMenus[i] DO
  1975.                     FOR j := 1 TO CountMItems(mh) DO
  1976.                     BEGIN
  1977.  
  1978.                         GetItemCmd(mh, j, cmdChar);
  1979.                         IF equalChars(cmdChar, ch) THEN
  1980.                         BEGIN
  1981.                             found := true;
  1982.                             whichMenu := mh^^.menuID;
  1983.                             whichItem := j;
  1984.                             Leave;   { FOR loop }
  1985.                         END;   { IF equalChars }
  1986.  
  1987.                     END;   { FOR scanning each individual Menu & WITH wMenus[i] }
  1988.  
  1989.                 i := i + 1;                       { IF found, i = correct # plus 1. }
  1990.  
  1991.             END;   { WHILE scanning each whole Menu }
  1992.  
  1993.             IF found THEN
  1994.             BEGIN
  1995.       { The Item is enabled if both it AND its Menu title are enabled: }
  1996.                 IF j < 32 THEN
  1997.                     enabled := BitTst(@wMenus[i - 1].mh^^.enableFlags, menuTitleBit - j)
  1998.                 ELSE
  1999.                     enabled := true;                { Items 32 & beyond. }
  2000.                 enabled := enabled & BitTst(@wMenus[i - 1].mh^^.enableFlags, menuTitleBit);
  2001.             END;   { IF found }
  2002.  
  2003.         END;   { WITH theMenuBar^^ }
  2004.  
  2005.         HSetState(Handle(theMenuBar), mbHState);
  2006.  
  2007.         IF found & enabled THEN
  2008.         BEGIN
  2009.             wHiliteMenu(theMenuBar, whichMenu);
  2010.             Delay(flashDelay, finalTicks);
  2011.             wHiliteMenu(theMenuBar, 0);
  2012.             wMenuKey := BitShift(whichMenu, 16) + whichItem;
  2013.         END   { IF found & enabled }
  2014.         ELSE
  2015.             wMenuKey := 0;
  2016.  
  2017.     END;   { wMenuKey }
  2018.  
  2019.  
  2020.     PROCEDURE wHiliteMenu (theMenuBar: wMenuBarHandle; menuID: INTEGER);
  2021. { NOTE that this PROC is used only for a regular Menu item. }
  2022. { Apple's MenuDefProc handles a hierarchical Menu item.     }
  2023. { For a regular Menu item, we invert the portion of the     }
  2024. { titleRect that is both totally visible on the screen and  }
  2025. { between the two MSAs.                                     }
  2026.  
  2027.         CONST
  2028.             HiliteMode = $938;           { What happened to a simple InvertRect ?!!? }
  2029.  
  2030.         VAR
  2031.             origPort: GrafPtr;
  2032.             origClip: RgnHandle;
  2033.             i: INTEGER;
  2034.             screenBounds, betweenMSAs, visAllTitles, visThisTitle, visString: Rect;
  2035.             lmbHState: SignedByte;       { Gotta be local to avoid interference }
  2036.                                    { with the global = mbHState.          }
  2037.             oldMCTable: MCTableHandle;   { Color stuff ... }
  2038.             oldForeColor, oldBackColor, hiliteForeColor, hiliteBackColor: RGBColor;
  2039.             oldTxSize, oldTxFont, oldTxMode: INTEGER;
  2040.             oldTxStyle: Style;
  2041.  
  2042.  
  2043.     BEGIN
  2044.  
  2045.   { Needed because wHiliteMenu is called with pressing }
  2046.   { a CMD-key whereupon a window may not be around.    }
  2047.         IF FrontWindow = NIL THEN
  2048.             EXIT(wHiliteMenu);
  2049.  
  2050.         lmbHState := HGetState(Handle(theMenuBar));
  2051.         IF NOT BitTst(@lmbHState, 0) THEN
  2052.         BEGIN
  2053.             MoveHHi(Handle(theMenuBar));
  2054.             HLock(Handle(theMenuBar));
  2055.         END;   { NOT already locked !! }
  2056.  
  2057.         WITH theMenuBar^^ DO
  2058.         BEGIN
  2059.             GetPort(origPort);
  2060.             SetPort(wp);
  2061.             origClip := NewRgn;
  2062.             GetClip(origClip);
  2063.             ;
  2064.             oldTxSize := thePort^.txSize;     { Just as with wMenuSelect PROC }
  2065.             oldTxFont := thePort^.txFont;     {   because wMenuKey calls us.  }
  2066.             oldTxStyle := thePort^.txFace;
  2067.             oldTxMode := thePort^.txMode;
  2068.             TextFont(systemFont);
  2069.             myTextSize(sizeFont);
  2070.             TextFace([]);
  2071.             TextMode(srcOr);
  2072.             ;
  2073.             IF aMac2 THEN
  2074.             BEGIN
  2075.                 GetForeColor(oldForeColor);
  2076.                 GetBackColor(oldBackColor);
  2077.                 oldMCTable := GetMCInfo;
  2078.                 SetMCInfo(theMenuBar^^.wMCTable);
  2079.             END;
  2080.  
  2081.             screenBounds := gScreen;
  2082.             GlobalLocal(screenBounds);
  2083.             betweenMSAs := WBMrect;
  2084.             InsetRect(betweenMSAs, leftMSArect.right, 0);   { ... or rightMSArect.left }
  2085.             IF SectRect(screenBounds, betweenMSAs, visAllTitles) THEN
  2086.             BEGIN
  2087.  
  2088.       { Un-highlight previously highlighted Menu title by re-inverting  }
  2089.       { it or re-drawing it if on a machine with Color QuickDraw.       }
  2090.       { This is similiar to the gyrations within Apple's MenuDefProc.   }
  2091.       { The latter does NOT call _InverRect for a color Mac, but rather }
  2092.       { _EraseRect followed by a redraw of the Menu item.               }
  2093.                 IF titleHilited <> noneHilited THEN
  2094.                 BEGIN
  2095.                     WITH wMenus[titleHilited], titleRect DO
  2096.                     BEGIN
  2097.                         IF SectRect(visAllTitles, titleRect, visThisTitle) THEN
  2098.                         BEGIN     { ALWAYS true if hilited. }
  2099.                             ClipRect(visThisTitle);
  2100.                             IF aMac2 THEN             { See wDrawMenuBar PROC. }
  2101.                             BEGIN
  2102.                                 wSetColorMenu(mceMenuBar, mceMenuBar);
  2103.                                 EraseRect(visThisTitle);
  2104.                                 MoveTo(left + invertOverlap, bottom - (mBarHt - menuFrame - sizeFont) DIV 2);
  2105.                                 wSetColorMenu(mh^^.menuID, mceMenuTitle);
  2106.                                 DrawString(mh^^.menuData);
  2107.                             END
  2108.                             ELSE
  2109.                                 InvertRect(visThisTitle);
  2110.                             ValidRect(visThisTitle);
  2111.                         END;   { IF SectRect: visThisTitle NOT empty }
  2112.                     END;   { WITH }
  2113.                     ;
  2114.                     titleHilited := noneHilited;   { So we don't re-invert. }
  2115.                 END;   { IF hilited }
  2116.  
  2117.                 IF menuID <> 0 THEN
  2118.                 BEGIN
  2119.                     i := 0;
  2120.                     WHILE (i < numMenus) & (wMenus[i].mh^^.menuID <> menuID) DO
  2121.                         i := i + 1;
  2122.  
  2123.                     IF i <> numMenus THEN
  2124.                         WITH wMenus[i] DO
  2125.                         BEGIN
  2126.                             IF SectRect(visAllTitles, titleRect, visThisTitle) THEN
  2127.                             BEGIN
  2128.                                 visString := visThisTitle;
  2129.                                 WITH visString DO
  2130.                                 BEGIN
  2131.                                     IF (leftMSArect.right > right - invertOverlap - 2 * menuFrame) | (screenBounds.left > right - invertOverlap - 2 * menuFrame) THEN
  2132.                                         right := right - invertOverlap - 2 * menuFrame;
  2133.                                     ;
  2134.                                     IF (rightMSArect.left < left + invertOverlap + 2 * menuFrame) | (screenBounds.right < left + invertOverlap + 2 * menuFrame) THEN
  2135.                                         left := left + invertOverlap + 2 * menuFrame;
  2136.                                 END;   { WITH visString }
  2137.  
  2138.                                 IF NOT EmptyRect(visString) THEN
  2139.                                 BEGIN
  2140.                                     ClipRect(visThisTitle);
  2141.                                     IF aMac2 THEN
  2142.                                     BEGIN
  2143.                   { Text's color becomes the background color and the  }
  2144.                   { MenuBar's background color becomes the foreground. }
  2145.                                         wSetColorMenu(menuID, mceMenuTitle);
  2146.                                         GetForeColor(hiliteBackColor);
  2147.                                         HiliteColor(hiliteBackColor);
  2148.                                         wSetColorMenu(mceMenuBar, mceMenuBar);
  2149.                   { GetBackColor(hiliteForeColor); }
  2150.                   { RGBBackColor(hiliteForeColor); }
  2151.                                         BitClr(Ptr(HiliteMode), pHiliteBit);
  2152.                                     END;   { on a color machine }
  2153.                                     InvertRect(visThisTitle);
  2154.                                     ValidRect(visThisTitle);
  2155.                                     ;
  2156.                                     titleHilited := i;
  2157.                                 END;   { visString NOT empty }
  2158.                             END;   { IF SectRect: visThisTitle NOT empty }
  2159.                         END;   { IF i <> numMenus & WITH }
  2160.                 END   { IF menuID <> 0 }
  2161.                 ELSE  { as in HiliteMenu(0). }
  2162.                     ;    { Taken care of by IF titleHilited <> noneHilited }
  2163.  
  2164.             END;   { IF SectRect: visAllTitles NOT empty }
  2165.  
  2166.             IF aMac2 THEN
  2167.             BEGIN
  2168.                 SetMCInfo(oldMCTable);
  2169.                 RGBForeColor(oldForeColor);
  2170.                 RGBBackColor(oldBackColor);
  2171.             END;
  2172.             ;
  2173.             TextFont(oldTxFont);
  2174.             myTextSize(oldTxSize);
  2175.             TextFace(oldTxStyle);
  2176.             TextMode(oldTxMode);
  2177.             ;
  2178.             SetClip(origClip);
  2179.             DisposeRgn(origClip);
  2180.             SetPort(origPort);
  2181.         END;   { WITH theMenuBar^^ }
  2182.  
  2183.         HSetState(Handle(theMenuBar), lmbHState);
  2184.  
  2185.     END;   { wHiliteMenu }
  2186.  
  2187.  
  2188.     PROCEDURE wChangeMenuBarSize (wp: WindowPtr; zooming: BOOLEAN);
  2189. { Called in response to zooming & growing the window. }
  2190. { Note: NOT zooming = growing.                        }
  2191.  
  2192.  
  2193.     BEGIN
  2194.  
  2195.         mBar := wGetMenuBar(wp);
  2196.         ;
  2197.         IF mBar <> NIL THEN
  2198.         BEGIN                                    { Only a part of wClearMenuBar ... }
  2199.             GetWBMrects(wp, WBMrect, leftMSArect, rightMSArect);
  2200.  
  2201.             wHiliteMenu(mBar, 0);
  2202.  
  2203.             IF NOT zooming THEN                   { doZoom calls InvalRect(wp^.portRect) }
  2204.                 InvalRect(rightMSArect);
  2205.  
  2206.             IF mBar^^.rightScrollPoly <> NIL THEN
  2207.             BEGIN
  2208.                 KillPoly(mBar^^.rightScrollPoly);
  2209.                 mBar^^.rightScrollPoly := NIL;       { Mark as gone !! }
  2210.             END;
  2211.  
  2212.             IF zooming & (mBar^^.leftScrollPoly <> NIL) THEN
  2213.             BEGIN
  2214.                 KillPoly(mBar^^.leftScrollPoly);
  2215.                 mBar^^.leftScrollPoly := NIL;
  2216.             END;
  2217.         END;   { window has a WBM }
  2218.  
  2219.     END;   { wChangeMenuBarSize }
  2220.  
  2221.  
  2222.  
  2223. END.   { UNIT = wBarMenuProc }